Create box function

Really useful for making boxes 👍

Pada tanggal 28 Juli 2023. Lihat %(latest_version_link).

You will need to install an extension such as Tampermonkey, Greasemonkey or Violentmonkey to install this script.

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

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

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

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

You will need to install a user script manager extension to install this script.

(I already have a user script manager, let me install it!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(I already have a user style manager, let me install it!)

// ==UserScript==
// @name         Create box function
// @namespace    create_box_owot
// @version      1.2
// @description  Really useful for making boxes 👍
// @author       e_g.
// @match        https://ourworldoftext.com/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=ourworldoftext.com
// @grant        none
// ==/UserScript==

setupModals = function(){
    //Help modal
    function makeBoxHelpModal(){
        var helpModal = new Modal();
        helpModal.createForm();
        helpModal.setFormTitle(`Arguments available (insert them inside an object):
x
y
width
height
borderSize
mainColor (0x)
borderColor (0x)
textColor (0x)
textBgColor (0x)
title
description
footer
titleAlign ("center", "left", "right")
descAlign ("center", "left", "right")
footerAlign ("center", "left", "right")
footer2space (makes the footer 2 spaces horizontally instead of 1, to make a more precise 1:1 space)
borderCollision (text will stick to the border instead of having 1 space)
fullActions (set to true to make borderSize extreme values or making a box bigger than 512 characters)

Arguments you should not use because they're not customizable and are important parts from the box creation:
size
formattedDesc
descIndex
titleFormula
descFormula
footerFormula`);
        helpModal.setMaximumSize(500, 600);
        w.ui.boxHelpModal = helpModal;
    }
    makeBoxHelpModal();
    //Box creator modal
    function makeBoxCreatorModal() {
        var modal = new Modal();
        modal.createForm();
        modal.createCheckboxField();
        modal.setFormTitle("Let's create a box!\n");
        for(var inputs of ["x", "y", "width", "height", "borderSize", "mainColor", "borderColor", "textColor", "textBgColor"]){
            window[inputs] = modal.addEntry(inputs, "text", "number").input;
        };
        for(var inputs of ["title", "description", "footer", "titleAlign", "descAlign", "footerAlign"]){
            window[inputs] = modal.addEntry(inputs, "text", "string").input;
        };
        modal.setMaximumSize(500, 600);
        for(var inputs of ["footer2space", "borderCollision", "fullActions"]){
            window[inputs] = modal.addCheckbox(inputs)
        };
        modal.onSubmit(function(){
            createBox({
                x: +x.value,
                y: +y.value,
                width: +width.value,
                height: +height.value,
                borderSize: +borderSize.value,
                mainColor: +mainColor.value,
                borderColor: +borderColor.value,
                textColor: +textColor.value,
                textBgColor: +textBgColor.value,
                title: title.value,
                description: description.value,
                footer: footer.value,
                titleAlign: titleAlign.value,
                descAlign: descAlign.value,
                footerAlign: footerAlign.value,
                footer2space: footer2space.cbElm.checked,
                borderCollision: borderCollision.cbElm.checked,
                fullActions: fullActions.cbElm.checked
            });
        });
        modal.client.firstChild.append(...modal.client.children[1].children);
        modal.client.firstChild.insertBefore(modal.client.firstChild.children[2], modal.client.firstChild.lastChild.nextSibling);
        w.ui.boxCreatorModal = modal;
    };
    makeBoxCreatorModal();
    //Create menu options
    menu.addOption("Help", function(){
        w.ui.boxHelpModal.open()
    });
    menu.addOption("Create box", function(){
        var region = RegionSelection();
        region.init();
        region.startSelection();
        region.onselection(function(xy, _, width, height){
            var options = w.ui.boxCreatorModal.client.children[0].children[1];
            options.children[1].value = xy[0] * 16 + xy[2];
            options.children[3].value = xy[1] * 8 + xy[3];
            options.children[5].value = width;
            options.children[7].value = height;
            w.ui.boxCreatorModal.open();
        });
    });
}
//Main menu option, that will setup the modals
menu.addEntry("<h1 onclick='setupModals();this.remove();'>Add box</h1>");

createBox = function(box){
    // Errors and warnings
    if(box.x === undefined) return console.error("X position isn't specified.");
    if(box.y === undefined) return console.error("Y position isn't specified.");
    if(box.width * box.height > 512 && !box.fullActions) return console.error("To make boxes bigger than 512 characters, add the arg fullActions and set it as true.");
    if(box.title.length > box.width - box.borderSize * 4 - !box.borderCollision * 2) return console.error("Title too big" + (box.title.length <= box.width - box.borderSize * 4 ? ", set borderCollision to true so you can use that title." : ""));
    if(box.footer && box.footer.length > box.width - box.borderSize * 4 - !box.borderCollision * 2 + box.footer2space) return console.error("Footer too big");
    if(box.borderSize * 4 >= box.width / 1.5 && !box.fullActions) return console.error("Box's main content is too small. Proceed by adding the arg fullActions to the args and setting it to true.");
    box.size = box.width * box.height + ((box.width - box.borderSize * 4) * (box.height - box.borderSize * 2)) * !!box.borderSize + box.title.length + box.description.length + (box.footer ? box.footer.length : 0);
    if(state.worldModel.char_rate.reduce((x, y) => x * y / 1e3) * 24 < box.size) return console.error("Your rate limit is too low to draw the box");
    if(state.worldModel.char_rate.reduce((x, y) => x * y / 1e3) * 2 < box.size) console.warn("The box might be messed up because your rate limit is too low for the box's size.");
    if(box.x % 1){
        box.x = Math.floor(box.x);
        console.warn(`The x value is a decimal value. It will be rounded to ${box.x}.`);
    };
    if(box.y % 1){
        box.y = Math.floor(box.y);
        console.warn(`The y value is a decimal value. It will be rounded to ${box.y}.`);
    };
    if(box.width % 1){
        box.width = Math.floor(box.width);
        console.warn(`The width size is a decimal value. It will be rounded to ${box.width}.`);
    };
    if(box.height % 1){
        box.height = Math.floor(box.height);
        console.warn(`The height size is a decimal value. It will be rounded to ${box.height}.`);
    };
    if(box.borderSize % 1){
        box.borderSize = Math.round(box.borderSize);
        console.warn(`The border size is a decimal value. It will be rounded to ${box.borderSize}.`);
    };
    if(box.borderSize * 4 >= box.width / 2) console.warn("Consider reducing border's size to add space for the main content!");
    if(box.footer2space && box.borderCollision) console.warn("Both footer2space and borderCollision are activated, this may cause conflict for the box.");
    // Avoid glitching when a word is too big for the box
    if(!box.description.endsWith(" ") && box.description.split(" ").at(-1).length > box.width - box.borderSize * 4 - 2) box.description += " ";
    // Rest of description's separating setup + see if it's too big for the box
    if(box.description.length > box.width - box.borderSize * 4 - !box.borderCollision * 2 && box.description.split(" ").length > 1){
        box.formattedDesc = [...box.description.match(RegExp(`.{0,${box.width - box.borderSize * 4 - !box.borderCollision * 2}} |.{${box.width - box.borderSize * 4 - !box.borderCollision * 2}}`, "g")), box.description.split(" ").at(-1)];
        if(box.formattedDesc.slice(-2).join("").length <= box.width - box.borderSize * 4 - !box.borderCollision * 2) box.formattedDesc = [...box.formattedDesc.slice(0, box.formattedDesc.length - 2), box.formattedDesc.slice(-2).join("")];
        box.formattedDesc = box.formattedDesc.map(x => x.replace(/ +$/, ""));
    }
    else box.formattedDesc = box.description.match(RegExp(`.{0,${box.width - box.borderSize * 4 - !box.borderCollision * 2}}`, "g"));
    box.formattedDesc = box.formattedDesc.filter(x => x != "");
    if(box.formattedDesc.length == 1 && box.formattedDesc[0] == "") box.formattedDesc = [];
    if(box.formattedDesc.length > box.height - box.borderSize * 2 - 2 - !box.borderCollision * 2 - !!box.footer * 2) return console.error("Description too long for the size of this box. Try setting borderCollision to true, or if that doesn't work, set a bigger size for the box or shorten the description.");
    //Make the box and box's border (reversed order)
    if(box.borderSize) filltoxy(box.x, box.y, box.width, box.height, "█", box.borderColor);
    filltoxy(box.x + box.borderSize * 2, box.y + box.borderSize, box.width - box.borderSize * 4, box.height - box.borderSize * 2, "█", box.mainColor);
    //Alignment formula of title and draw it
    if(!box.titleAlign) box.titleAlign = "center";
    if(box.titleAlign == "center"){
        box.titleFormula = Math.ceil(box.x + box.width / 2 - box.title.length / 2);
    }
    else if(box.titleAlign == "left"){
        box.titleFormula = Math.ceil(box.x + box.borderSize * 2 + !box.borderCollision);
    }
    else if(box.titleAlign == "right"){
        box.titleFormula = Math.ceil(box.x + (box.width - box.borderSize * 2 - !box.borderCollision - box.title.length));
    }
    else{
        console.warn("titleAlign had an invalid align, and was automatically assigned to center (the valid ones are: center, left, right)");
        box.titleAlign = "center";
        box.titleFormula = Math.ceil(box.x + box.width / 2 - box.title.length / 2);
    };
    texttoxy(box.titleFormula, box.y + box.borderSize + !box.borderCollision, box.title, box.textColor, box.textBgColor);
    //Alignment formula of description and draw it
    if(!box.descAlign) box.descAlign = "center";
    if(box.descAlign == "center"){
        box.descFormula = function(formattedDesc, descIndex){
            return Math.ceil(box.x + box.width / 2 - formattedDesc[descIndex - box.borderSize - 3].length / 2);
        };
    }
    else if(box.descAlign == "left"){
        box.descFormula = function(){
            return Math.ceil(box.x + box.borderSize * 2 + !box.borderCollision);
        };
    }
    else if(box.descAlign == "right"){
        box.descFormula = function(formattedDesc, descIndex){
            return Math.ceil(box.x + (box.width - box.borderSize * 2 - !box.borderCollision - formattedDesc[descIndex - box.borderSize - 3].length));
        };
    }
    else{
        console.warn("descAlign had an invalid align, and was automatically assigned to center (the valid ones are: center, left, right)");
        box.descAlign = "center";
        box.descFormula = function(formattedDesc, descIndex){
            return Math.ceil(box.x + box.width / 2 - formattedDesc[descIndex - box.borderSize - 3].length / 2);
        };
    };
    for(box.descIndex = box.borderSize + 3; box.descIndex < box.formattedDesc.length + box.borderSize + 3; box.descIndex++){
        texttoxy(box.descFormula(box.formattedDesc, box.descIndex), box.y + box.descIndex - !!box.borderCollision, box.formattedDesc[box.descIndex - box.borderSize - 3], box.textColor, box.textBgColor);
    };
    //Alignment formula of footer and draw it IF there's any
    if(!box.footer) return;
    if(!box.footerAlign) box.footerAlign = "right";
    if(box.footerAlign == "center"){
        box.footerFormula = Math.ceil(box.x + box.width / 2 - box.footer.length / 2);
    }
    else if(box.footerAlign == "left"){
        box.footerFormula = Math.ceil(box.x + box.borderSize * 2 + !box.borderCollision + !!box.footer2space);
    }
    else if(box.footerAlign == "right"){
        box.footerFormula = Math.ceil(box.x + (box.width - box.borderSize * 2 - !box.borderCollision - !!box.footer2space - box.footer.length));
    }
    else{
        console.warn("footerAlign had an invalid align, and was automatically assigned to right (the valid ones are: center, left, right)");
        box.footerAlign = "right";
        box.footerFormula = Math.ceil(box.x + (box.width - box.borderSize * 2 - !box.borderCollision - !!box.footer2space - box.footer.length));
    };
    texttoxy(box.footerFormula, box.y + box.height - box.borderSize - 1 - !box.borderCollision, box.footer, box.textColor, box.textBgColor);
}