Hornex Build Saver+

Click button to save/load your build.

// ==UserScript==
// @name           Hornex Build Saver+
// @name:ja        hornex ビルド保存&配置スクリプト
// @namespace      http://tampermonkey.net/
// @version        3.0.2
// @description    Click button to save/load your build.
// @description:ja 左のボタンを押してビルドを保存&配置できます。
// @author         AstRatJP
// @author         aragami070
// @match          https://hornex.pro/*
// @license        MIT
// @grant          none
// ==/UserScript==

let numBuildsLimit = 10
let minNumBuilds = 1

/*
READ ME:
-The original script is by AstRatJP
-https://greasyfork.org/en/scripts/475349-hornex-build-saver
-Don't change the following codes unless you know what are you doing, they exist for a reason.
*/

let numBuilds = localStorage.getItem('HBSsavedNumBuilds');
if (!numBuilds) {
    localStorage.setItem(`HBSsavedNumBuilds`, 5);
    numBuilds = localStorage.getItem('HBSsavedNumBuilds');
}
const nameLenLimit = 50; //this is to prevent you being stupid and blow up your own pc by putting a whole essay

let rnames = [];
let sbuttons = []
let lbuttons = []

for (let i=1; i<=numBuildsLimit; i++) {
    let savedName = localStorage.getItem(`HBSr${i}savedname`);
    if (!savedName) {
        savedName = i.toString();
        localStorage.setItem(`HBSr${i}savedname`, savedName);
    }
    rnames.push(savedName)
}

console.log('Found saved build names: '+rnames)

let containerDiv = document.createElement('div');
containerDiv.style.width = '55px';
containerDiv.style.alignItems = 'start';
containerDiv.style.gridAutoFlow = 'column';
containerDiv.style.display = 'grid';
document.querySelector(".btn.shop-btn").before(containerDiv);

let addBTN = document.createElement('div');
addBTN.classList.add("btn");
addBTN.style.backgroundColor = "lime";
addBTN.textContent = "+";
addBTN.style.height = '7px';
addBTN.style.width = '7px';
addBTN.style.padding = '5px 5px';
addBTN.addEventListener('click', () => { addBuild() });
addBTN.addEventListener('touchstart', () => { addBuild() });
containerDiv.appendChild(addBTN);
let removeBBtn = document.createElement('div');
removeBBtn.classList.add("btn");
removeBBtn.style.backgroundColor = "red";
removeBBtn.textContent = "-";
removeBBtn.style.height = '7px';
removeBBtn.style.width = '7px';
removeBBtn.style.padding = '5px 5px';
removeBBtn.addEventListener('click', () => { removeBuild() });
removeBBtn.addEventListener('touchstart', () => { removeBuild() });
containerDiv.appendChild(removeBBtn);

// rename button
let renameBTN = document.createElement('div');
renameBTN.classList.add("btn");
renameBTN.style.backgroundColor = "#BBBBBB";
renameBTN.textContent = "Rename";
renameBTN.style.height = '10px'
renameBTN.addEventListener('click', () => { renameBuild() });
renameBTN.addEventListener('touchstart', () => { renameBuild() });
document.querySelector(".btn.shop-btn").before(renameBTN);

// toggle button
let toggleBTN = document.createElement('div');
toggleBTN.classList.add("btn");
toggleBTN.style.backgroundColor = "#BBBBBB";
toggleBTN.textContent = "Toggle";
toggleBTN.style.height = '10px'
toggleBTN.addEventListener('click', () => { toggleButton() });
toggleBTN.addEventListener('touchstart', () => { toggleButton() });
document.querySelector(".btn.shop-btn").before(toggleBTN);

// remove button
let removeBTN = document.createElement('div');
removeBTN.classList.add("btn");
removeBTN.style.backgroundColor = "tomato";
removeBTN.textContent = "Clear Row";
removeBTN.style.height = '10px'
removeBTN.addEventListener('click', () => { removePrimaryPetals() });
removeBTN.addEventListener('touchstart', () => { removePrimaryPetals() });
document.querySelector(".btn.shop-btn").before(removeBTN);

for (let i=1; i<=numBuilds; i++) {
    let buildS = document.createElement('div');
    buildS.classList.add("btn", `s${i}`, "hidden");
    buildS.textContent = `Save ${rnames[i-1]}`;
    buildS.style.height = '10px'
    buildS.addEventListener('click', () => { saveBuild(i) });
    buildS.addEventListener('touchstart', () => { saveBuild(i) });
    document.querySelector(".btn.shop-btn").before(buildS);
    sbuttons.push(buildS);
};

for (let i=1; i<=numBuilds; i++) {
    let buildL = document.createElement('div');
    buildL.classList.add("btn");
    buildL.textContent = rnames[i-1];
    buildL.style.height = '10px'
    buildL.addEventListener('click', () => { setBuild(i) });
    buildL.addEventListener('touchstart', () => { setBuild(i) });
    document.querySelector(".btn.shop-btn").before(buildL);
    lbuttons.push(buildL);
};

const styleHidden = document.createElement('style');
styleHidden.innerHTML = ".hidden { display: none !important; } ";
document.body.appendChild(styleHidden);

const input = document.querySelector('.chat-input');
const inputName = document.querySelector('.grid .nickname');
let chatFocus = false;
let nameFocus = false;
let mouseMoved = false;


input.addEventListener('focus', () => {
    chatFocus = true;
});
inputName.addEventListener('focus', () => {
    nameFocus = true;
});
input.addEventListener('blur', () => {
    chatFocus = false;
})
inputName.addEventListener('blur', () => {
    nameFocus = false;
});
document.addEventListener('mousemove', () => {
    mouseMoved = true;
});


async function removePrimaryPetals() {
    const elements = Array.from(document.querySelectorAll(".petals:not(.small) .petal.empty .petal"));
    for (let i = 0; i < elements.length; i++) {
        const element = elements[i];
        const slot = document.querySelector(".petal-rows");
        const longPressEvent = new MouseEvent("mousedown", {
            bubbles: true,
            cancelable: true,
            view: window,
            buttons: 1,
            button: 0,
        });
        const mouseUpEvent = new MouseEvent("mouseup", {
            bubbles: true,
            cancelable: true,
            view: window,
            buttons: 0,
        });
        element.dispatchEvent(longPressEvent);
        const top = element.style.top;
        const left = element.style.left;


        const endTime = Date.now() + 500;
        mouseMoved = false;
        while (Date.now() < endTime) {
            if (mouseMoved) {
                break;
            }
            await new Promise(resolve => setTimeout(resolve, 1));
        }



        let slotTop = slot.style.top;
        slot.style.top = "0%";
        element.dispatchEvent(mouseUpEvent);
        slot.style.top = slotTop;
    }
}


async function removeAllPetals() {
    const elements = Array.from(document.querySelectorAll(".petals .petal.empty .petal"));
    for (let i = 0; i < elements.length; i++) {
        const element = elements[i];
        const slot = document.querySelector(".petal-rows");
        const longPressEvent = new MouseEvent("mousedown", {
            bubbles: true,
            cancelable: true,
            view: window,
            buttons: 1,
            button: 0,
        });
        const mouseUpEvent = new MouseEvent("mouseup", {
            bubbles: true,
            cancelable: true,
            view: window,
            buttons: 0,
        });
        element.dispatchEvent(longPressEvent);
        const top = element.style.top;
        const left = element.style.left;


        const endTime = Date.now() + 500;
        mouseMoved = false;
        while (Date.now() < endTime) {
            if (mouseMoved) {
                break;
            }
            await new Promise(resolve => setTimeout(resolve, 1));
        }



        let slotTop = slot.style.top;
        slot.style.top = "0%";
        element.dispatchEvent(mouseUpEvent);
        slot.style.top = slotTop;
    }
}





function saveBuild(i) {
    let petalPosition = "";
    let tier = "";
    const petals = Array.from(document.querySelectorAll(".petals .petal.empty .petal"));
    const savedBuild = [];
    for (let i = 0; i < petals.length; i++) {
        if (petals[i].classList.item(2) === "no-icon" || petals[i].classList.item(3) === "no-icon") {
            petalPosition = petals[i].querySelector(".petal-icon").style.backgroundPosition;
        } else {
            petalPosition = petals[i].style.backgroundPosition;
        }
        if (petals[i].classList.item(1) === "spin") {
            tier = petals[i].classList.item(2);
        } else {
            tier = petals[i].classList.item(1);
        }
        savedBuild.push(petalPosition, tier);
    }
    localStorage.setItem(`savedBuild${i}`, JSON.stringify(savedBuild));
    if (document.querySelector(`.s${i}`).textContent !== "Saved!") {
        const oldText = document.querySelector(`.s${i}`).textContent.toString();
        document.querySelector(`.s${i}`).textContent = "Saved!";
        setTimeout(()=>{ document.querySelector(`.s${i}`).textContent = oldText; }, 1000);
    }
}


function setPetal(petalPosition, tier) {
    const petal = document.querySelector(`.common [style*="background-position: ${petalPosition}"].${tier}`);

    const longPressEvent = new MouseEvent("mousedown", {
        bubbles: true,
        cancelable: true,
        view: window,
        buttons: 1,
        button: 0,
    });
    const mouseUpEvent = new MouseEvent("mouseup", {
        bubbles: true,
        cancelable: true,
        view: window,
        buttons: 0,
    });
    petal.dispatchEvent(longPressEvent);
    petal.dispatchEvent(mouseUpEvent);
}

function closeInventory() {
    const closeBtn = document.querySelector(".dialog.inventory .btn.close-btn");

    const clickEvent = new MouseEvent('click', {
        'view': window,
        'bubbles': true,
        'cancelable': true
    });
    closeBtn.dispatchEvent(clickEvent);
}

async function setBuild(i) {
    const savedBuild = JSON.parse(localStorage.getItem(`savedBuild${i}`));
    await removeAllPetals();
    for (let i = 0; i < savedBuild.length; i += 2) {
        setPetal(savedBuild[i], savedBuild[i + 1]);
    }
    await closeInventory();
}

function renameBuild() {
    let build = prompt('Build no. to rename: ');
    build = parseInt(build);
    if ( build===null ) { return; } else if ( build>parseInt(localStorage.getItem('HBSsavedNumBuilds')) || build<1 || isNaN(build) ) {
        alert('Invalid build #!');
        return;
    }

    const name = prompt('New name: ');
    if ( name===null ) { return; } else if ( name.length > nameLenLimit) {
        alert('Too long!');
        return;
    }

    localStorage.setItem(`HBSr${build}savedname`, name)

    sbuttons[build-1].textContent = 'Save '+name;
    lbuttons[build-1].textContent = name;

    console.log(`Successfully renamed build ${build} to ${name}`)
}

function toggleButton() {
    for (let i=0; i<=(parseInt(localStorage.getItem('HBSsavedNumBuilds'))-1); i++) {
        sbuttons[i].classList.toggle('hidden');
        lbuttons[i].classList.toggle('hidden');
    };
}

function addBuild() {
    const currentNumBuilds = parseInt(localStorage.getItem('HBSsavedNumBuilds'));
    if (currentNumBuilds>=numBuildsLimit) {
        localStorage.setItem(`HBSsavedNumBuilds`, numBuildsLimit);
        return;
    }
    localStorage.setItem(`HBSsavedNumBuilds`, currentNumBuilds+1);
    let buildS = document.createElement('div');
    buildS.classList.add("btn", `s${currentNumBuilds+1}`, "hidden");
    buildS.textContent = `Save ${localStorage.getItem(`HBSr${currentNumBuilds+1}savedname`)}`;
    buildS.style.height = '10px'
    buildS.addEventListener('click', () => { saveBuild(currentNumBuilds+1) });
    buildS.addEventListener('touchstart', () => { saveBuild(currentNumBuilds+1) });
    document.querySelector(".btn.shop-btn").before(buildS);
    sbuttons.push(buildS);
    let buildL = document.createElement('div');
    buildL.classList.add("btn");
    buildL.textContent = localStorage.getItem(`HBSr${currentNumBuilds+1}savedname`);
    buildL.style.height = '10px'
    buildL.addEventListener('click', () => { setBuild(currentNumBuilds+1) });
    buildL.addEventListener('touchstart', () => { setBuild(currentNumBuilds+1) });
    document.querySelector(".btn.shop-btn").before(buildL);
    lbuttons.push(buildL);
    console.log('added 1 build')
}

function removeBuild() {
    const currentNumBuilds = parseInt(localStorage.getItem('HBSsavedNumBuilds'));
    if (currentNumBuilds<=minNumBuilds) {
        localStorage.setItem(`HBSsavedNumBuilds`, minNumBuilds);
        return;
    }
    localStorage.setItem(`HBSsavedNumBuilds`, currentNumBuilds-1);
    sbuttons[currentNumBuilds-1].remove();
    lbuttons[currentNumBuilds-1].remove();
    sbuttons.pop();
    lbuttons.pop();
    console.log('removed 1 build')
}