Create box function

Really useful for making boxes 👍

当前为 2023-07-28 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name Create box function
  3. // @namespace create_box_owot
  4. // @version 1.3
  5. // @description Really useful for making boxes 👍
  6. // @author e_g.
  7. // @match https://ourworldoftext.com/*
  8. // @icon https://www.google.com/s2/favicons?sz=64&domain=ourworldoftext.com
  9. // @grant none
  10. // ==/UserScript==
  11.  
  12. setupModals = function(){
  13. //Box creator modal
  14. function makeBoxCreatorModal() {
  15. var modal = new Modal();
  16. modal.createForm();
  17. modal.createCheckboxField();
  18. modal.setFormTitle("Let's create a box!\n");
  19. for(var inputs of ["x", "y", "width", "height", "borderSize"]){
  20. window[inputs] = modal.addEntry(inputs, "text", "number").input;
  21. };
  22. for(var inputs of ["mainColor", "borderColor", "textColor", "textBgColor"]){
  23. window[inputs] = modal.addEntry(inputs, "color").input;
  24. };
  25. for(var inputs of ["title", "description", "footer"]){
  26. window[inputs] = modal.addEntry(inputs, "text", "string").input;
  27. };
  28. for(var inputs of ["titleAlign", "descAlign", "footerAlign"]){ //thanks poopman
  29. window[inputs+"Options"] = [
  30. { label: "Left", value: "left"},
  31. { label: "Center", value: "center", default: (inputs == "footerAlign" ? false : true) },
  32. { label: "Right", value: "right", default: (inputs == "footerAlign" ? true : false)},
  33. ];
  34. window[inputs] = (inputs == "footerAlign" ? "right" : "center");
  35. createRadioButtons(modal, inputs, window[inputs+"Options"]);
  36. }; //poopman's part stops here
  37. modal.setMaximumSize(500, 600);
  38. for(var inputs of ["footer2space", "borderCollision", "fullActions"]){
  39. window[inputs] = modal.addCheckbox(inputs)
  40. window[inputs].cbElm.title = {
  41. footer2space: "2 horizontal spaces instead of 1. Doesn't apply when using centered footer.",
  42. borderCollision: "Makes the text stick to the border instead of having a spacement.",
  43. fullActions: "Makes you able to make bigger borders or make boxes bigger than 512 characters."
  44. }[inputs];
  45. };
  46. modal.onSubmit(function(){
  47. createBox({
  48. x: +x.value,
  49. y: +y.value,
  50. width: +width.value,
  51. height: +height.value,
  52. borderSize: +borderSize.value,
  53. mainColor: parseInt(mainColor.value, 16),
  54. borderColor: parseInt(borderColor.value, 16),
  55. textColor: parseInt(textColor.value, 16),
  56. textBgColor: parseInt(textBgColor.value, 16),
  57. title: title.value,
  58. description: description.value,
  59. footer: footer.value,
  60. titleAlign: document.querySelector('input[name="titleAlign"]:checked').value, //thanks poopman
  61. descAlign: document.querySelector('input[name="descAlign"]:checked').value,
  62. footerAlign: document.querySelector('input[name="footerAlign"]:checked').value, //poopman's part stops here
  63. footer2space: footer2space.cbElm.checked,
  64. borderCollision: borderCollision.cbElm.checked,
  65. fullActions: fullActions.cbElm.checked
  66. });
  67. });
  68. modal.client.firstChild.append(...modal.client.children[1].children);
  69. modal.client.firstChild.insertBefore(modal.client.firstChild.children[2], modal.client.firstChild.lastChild.nextSibling);
  70. w.ui.boxCreatorModal = modal;
  71. };
  72. makeBoxCreatorModal();
  73. function createRadioButtons(modal, name, options) { //thanks poopman
  74. const radioDiv = document.createElement("div");
  75. radioDiv.style.display = "flex";
  76. const radioText = document.createElement("label");
  77. radioText.innerHTML = name + ":";
  78. radioDiv.appendChild(radioText);
  79. for (const option of options) {
  80. const label = document.createElement("label");
  81. label.style.marginRight = "10px";
  82. const input = document.createElement("input");
  83. input.type = "radio";
  84. input.name = name;
  85. input.value = option.value;
  86. if (option.default) {
  87. input.checked = true;
  88. }
  89. label.appendChild(input);
  90. label.appendChild(document.createTextNode(option.label));
  91. radioDiv.appendChild(label);
  92. }
  93. modal.formField.appendChild(radioDiv);
  94. } //poopman's part stops here
  95. //Create menu option
  96. menu.addOption("Create box", function(){
  97. var region = RegionSelection();
  98. region.init();
  99. region.startSelection();
  100. region.onselection(function(xy, _, width, height){
  101. var options = w.ui.boxCreatorModal.client.firstChild.children[1];
  102. options.children[1].value = xy[0] * 16 + xy[2];
  103. options.children[3].value = xy[1] * 8 + xy[3];
  104. options.children[5].value = width;
  105. options.children[7].value = height;
  106. w.ui.boxCreatorModal.open();
  107. });
  108. });
  109. }
  110. setupModals();
  111.  
  112. createBox = function(box){
  113. // Errors and warnings
  114. if(box.x === undefined) return console.error("X position isn't specified.");
  115. if(box.y === undefined) return console.error("Y position isn't specified.");
  116. 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.");
  117. 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." : ""));
  118. if(box.footer && box.footer.length > box.width - box.borderSize * 4 - !box.borderCollision * 2 + box.footer2space) return console.error("Footer too big");
  119. 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.");
  120. 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);
  121. 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");
  122. 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.");
  123. if(box.x % 1){
  124. box.x = Math.floor(box.x);
  125. console.warn(`The x value is a decimal value. It will be rounded to ${box.x}.`);
  126. };
  127. if(box.y % 1){
  128. box.y = Math.floor(box.y);
  129. console.warn(`The y value is a decimal value. It will be rounded to ${box.y}.`);
  130. };
  131. if(box.width % 1){
  132. box.width = Math.floor(box.width);
  133. console.warn(`The width size is a decimal value. It will be rounded to ${box.width}.`);
  134. };
  135. if(box.height % 1){
  136. box.height = Math.floor(box.height);
  137. console.warn(`The height size is a decimal value. It will be rounded to ${box.height}.`);
  138. };
  139. if(box.borderSize % 1){
  140. box.borderSize = Math.round(box.borderSize);
  141. console.warn(`The border size is a decimal value. It will be rounded to ${box.borderSize}.`);
  142. };
  143. if(box.borderSize * 4 >= box.width / 2) console.warn("Consider reducing border's size to add space for the main content!");
  144. if(box.footer2space && box.borderCollision) console.warn("Both footer2space and borderCollision are activated, this may cause conflict for the box.");
  145. // Avoid glitching when a word is too big for the box
  146. if(!box.description.endsWith(" ") && box.description.split(" ").at(-1).length > box.width - box.borderSize * 4 - 2) box.description += " ";
  147. // Rest of description's separating setup + see if it's too big for the box
  148. if(box.description.length > box.width - box.borderSize * 4 - !box.borderCollision * 2 && box.description.split(" ").length > 1){
  149. 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)];
  150. 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("")];
  151. box.formattedDesc = box.formattedDesc.map(x => x.replace(/ +$/, ""));
  152. }
  153. else box.formattedDesc = box.description.match(RegExp(`.{0,${box.width - box.borderSize * 4 - !box.borderCollision * 2}}`, "g"));
  154. box.formattedDesc = box.formattedDesc.filter(x => x != "");
  155. if(box.formattedDesc.length == 1 && box.formattedDesc[0] == "") box.formattedDesc = [];
  156. 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.");
  157. //Make the box and box's border (reversed order)
  158. if(box.borderSize) filltoxy(box.x, box.y, box.width, box.height, "█", box.borderColor);
  159. filltoxy(box.x + box.borderSize * 2, box.y + box.borderSize, box.width - box.borderSize * 4, box.height - box.borderSize * 2, "█", box.mainColor);
  160. //Alignment formula of title and draw it
  161. if(!box.titleAlign) box.titleAlign = "center";
  162. if(box.titleAlign == "center"){
  163. box.titleFormula = Math.ceil(box.x + box.width / 2 - box.title.length / 2);
  164. }
  165. else if(box.titleAlign == "left"){
  166. box.titleFormula = Math.ceil(box.x + box.borderSize * 2 + !box.borderCollision);
  167. }
  168. else if(box.titleAlign == "right"){
  169. box.titleFormula = Math.ceil(box.x + (box.width - box.borderSize * 2 - !box.borderCollision - box.title.length));
  170. }
  171. else{
  172. console.warn("titleAlign had an invalid align, and was automatically assigned to center (the valid ones are: center, left, right)");
  173. box.titleAlign = "center";
  174. box.titleFormula = Math.ceil(box.x + box.width / 2 - box.title.length / 2);
  175. };
  176. texttoxy(box.titleFormula, box.y + box.borderSize + !box.borderCollision, box.title, box.textColor, box.textBgColor);
  177. //Alignment formula of description and draw it
  178. if(!box.descAlign) box.descAlign = "center";
  179. if(box.descAlign == "center"){
  180. box.descFormula = function(formattedDesc, descIndex){
  181. return Math.ceil(box.x + box.width / 2 - formattedDesc[descIndex - box.borderSize - 3].length / 2);
  182. };
  183. }
  184. else if(box.descAlign == "left"){
  185. box.descFormula = function(){
  186. return Math.ceil(box.x + box.borderSize * 2 + !box.borderCollision);
  187. };
  188. }
  189. else if(box.descAlign == "right"){
  190. box.descFormula = function(formattedDesc, descIndex){
  191. return Math.ceil(box.x + (box.width - box.borderSize * 2 - !box.borderCollision - formattedDesc[descIndex - box.borderSize - 3].length));
  192. };
  193. }
  194. else{
  195. console.warn("descAlign had an invalid align, and was automatically assigned to center (the valid ones are: center, left, right)");
  196. box.descAlign = "center";
  197. box.descFormula = function(formattedDesc, descIndex){
  198. return Math.ceil(box.x + box.width / 2 - formattedDesc[descIndex - box.borderSize - 3].length / 2);
  199. };
  200. };
  201. for(box.descIndex = box.borderSize + 3; box.descIndex < box.formattedDesc.length + box.borderSize + 3; box.descIndex++){
  202. texttoxy(box.descFormula(box.formattedDesc, box.descIndex), box.y + box.descIndex - !!box.borderCollision, box.formattedDesc[box.descIndex - box.borderSize - 3], box.textColor, box.textBgColor);
  203. };
  204. //Alignment formula of footer and draw it IF there's any
  205. if(!box.footer) return;
  206. if(!box.footerAlign) box.footerAlign = "right";
  207. if(box.footerAlign == "center"){
  208. box.footerFormula = Math.ceil(box.x + box.width / 2 - box.footer.length / 2);
  209. }
  210. else if(box.footerAlign == "left"){
  211. box.footerFormula = Math.ceil(box.x + box.borderSize * 2 + !box.borderCollision + !!box.footer2space);
  212. }
  213. else if(box.footerAlign == "right"){
  214. box.footerFormula = Math.ceil(box.x + (box.width - box.borderSize * 2 - !box.borderCollision - !!box.footer2space - box.footer.length));
  215. }
  216. else{
  217. console.warn("footerAlign had an invalid align, and was automatically assigned to right (the valid ones are: center, left, right)");
  218. box.footerAlign = "right";
  219. box.footerFormula = Math.ceil(box.x + (box.width - box.borderSize * 2 - !box.borderCollision - !!box.footer2space - box.footer.length));
  220. };
  221. texttoxy(box.footerFormula, box.y + box.height - box.borderSize - 1 - !box.borderCollision, box.footer, box.textColor, box.textBgColor);
  222. }