TurboWarp / extensions

User-contributed unsandboxed extension gallery for TurboWarp
https://extensions.turbowarp.org/
MIT License
114 stars 231 forks source link

Create Variable Blocks #1103

Closed The-Best-Codes closed 3 weeks ago

The-Best-Codes commented 10 months ago

I have a code for an extension that will create or delete variables in the editor:

 class VariableExtension {
  constructor(runtime) {
    this.runtime = runtime;
  }

  getInfo() {
    return {
      id: 'variableExtension',
      name: 'Variable Extension',
      blocks: [
        {
          opcode: 'createVariable',
          blockType: 'command',
          text: 'create variable [variableName]',
          arguments: {
            variableName: {
              type: 'string',
              defaultValue: 'myVariable'
            }
          }
        },
        {
          opcode: 'renameVariable',
          blockType: 'command',
          text: 'rename variable [variableName] to [newName]',
          arguments: {
            variableName: {
              type: 'string',
              defaultValue: 'myVariable'
            },
            newName: {
              type: 'string',
              defaultValue: 'newVariableName'
            }
          }
        },
        {
          opcode: 'deleteVariable',
          blockType: 'command',
          text: 'delete variable [variableName]',
          arguments: {
            variableName: {
              type: 'string',
              defaultValue: 'myVariable'
            }
          }
        }
      ]
    };
  }

  createVariable(args, util) {
    const variableName = args.variableName;
    Blockly.getMainWorkspace().createVariable(variableName);
  }

  renameVariable(args, util) {
    const variableName = args.variableName;
    const newName = args.newName;
    const variable = Blockly.getMainWorkspace().getVariable(variableName);
    if (variable) {
      Blockly.getMainWorkspace().renameVariableById(variable.getId(), newName);
    }
  }

  deleteVariable(args, util) {
    const variableName = args.variableName;
    const variable = Blockly.getMainWorkspace().getVariable(variableName);
    if (variable) {
      Blockly.getMainWorkspace().deleteVariableById(variable.getId());
    }
  }
}

Scratch.extensions.register(new VariableExtension());
CubesterYT commented 10 months ago

Yo actually, this seems really useful!

softedco commented 10 months ago

how do you read them though, also dynamically

CubesterYT commented 10 months ago

@softedco, Have you tried the extension? It makes an actual new variable:

https://github.com/TurboWarp/extensions/assets/78769806/5211587c-14f1-4d8f-b085-de0c7b599c84

softedco commented 10 months ago

@softedco, Have you tried the extension? It makes an actual new variable:

https://github.com/TurboWarp/extensions/assets/78769806/5211587c-14f1-4d8f-b085-de0c7b599c84

you can't read it's value or set it dynamically, only manually which may only be useful in the editor

LilyMakesThings commented 10 months ago

@softedco, Have you tried the extension? It makes an actual new variable:

image

CubesterYT commented 10 months ago

I have a solution to that problem, but I won't get into it right now because I need to sleep, I've been working for hours 💀

softedco commented 10 months ago

@softedco, Have you tried the extension? It makes an actual new variable:

image

this

CubesterYT commented 10 months ago

Ok, I'm back, I forgot where this was, but this extension can be merged with the var and list extension, as it makes sense and works perfectly with that extension.

CubesterYT commented 10 months ago

https://github.com/TurboWarp/extensions/assets/78769806/661ec6f9-9f24-478b-8e47-79a1393b9078

Video of it working perfectly!!!

CubesterYT commented 10 months ago

Finally, vars and list extension will be finally be useful for me if this little extension is merged with vars and lists.

CubesterYT commented 10 months ago

Now there just has to be the same set of blocks here, but for lists, and we're golden.

MaxttcYT commented 10 months ago

Wow,we need this!

Stiwen02 commented 9 months ago

That's really cool! I also suggest you adding a block that makes a variable for a single sprite only and if a variable name is available, probably something like this: image image Also I'm not sure if the extension would work if it's packaged, but maybe the packaged .html file contains a copy of Blockly.

Bluecube5997thefan commented 6 months ago

Thats nice! It was used to make stc better.

Bluecube5997thefan commented 6 months ago

@softedco, Have you tried the extension? It makes an actual new variable:

image

It looks like your block disable that abilty. heres my code :) // Name: Variables Expanded // ID: DICandSPmonitorsPlus // Description: Expansion of Monitor Types and Variable Blocks. // By: SharkPool and DogeIsCut

// Version 1.2.3

(function (Scratch) { "use strict";

if (!Scratch.extensions.unsandboxed) throw new Error("Variables Expanded must run unsandboxed!");

const vm = Scratch.vm; const runtime = vm.runtime;

const menuIconURI = "data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHdpZHRoPSIzMjEiIGhlaWdodD0iMzIxIiB2aWV3Qm94PSIwLDAsMzIxLDMyMSI+PGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTc5LjUsLTE5LjUpIj48ZyBkYXRhLXBhcGVyLWRhdGE9InsmcXVvdDtpc1BhaW50aW5nTGF5ZXImcXVvdDs6dHJ1ZX0iIHN0cm9rZS1saW5lY2FwPSJidXR0IiBzdHJva2UtbGluZWpvaW49Im1pdGVyIiBzdHJva2UtbWl0ZXJsaW1pdD0iMTAiIHN0cm9rZS1kYXNoYXJyYXk9IiIgc3Ryb2tlLWRhc2hvZmZzZXQ9IjAiIHN0eWxlPSJtaXgtYmxlbmQtbW9kZTogbm9ybWFsIj48cGF0aCBkPSJNOTQsMTgwYzAsLTgwLjYzMzU3IDY1LjM2NjQyLC0xNDYgMTQ2LC0xNDZjODAuNjMzNTgsMCAxNDYsNjUuMzY2NDMgMTQ2LDE0NmMwLDgwLjYzMzU4IC02NS4zNjY0MiwxNDYgLTE0NiwxNDZjLTgwLjYzMzU4LDAgLTE0NiwtNjUuMzY2NDIgLTE0NiwtMTQ2eiIgZmlsbD0iI2ZmOGMxYSIgZmlsbC1ydWxlPSJub256ZXJvIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMCIvPjxwYXRoIGQ9Ik0xNjkuMDg3MzIsODQuMDM5NzRjNi4yMTQ2MSwyLjczMDg3IDkuMDQ1MDIsOS45Nzc2MyA2LjMyNjQyLDE2LjE5NzYxYy05LjQ4MDc2LDIxLjc0MDEgLTE0LjM1NDY2LDQ1LjIwODYxIC0xNC4zMTQ0NSw2OC45MjYwMmMwLDI0LjUzMDI3IDUuMTIwMjEsNDcuODI5NzMgMTQuMzI2NzYsNjguOTI2MDJjMi40NzI4OSw2LjE3MzU1IC0wLjQwNTQxLDEzLjE5NDk2IC02LjUwMDA2LDE1Ljg1NjM4Yy02LjA5NDY0LDIuNjYxNDIgLTEzLjIwMTE4LDAuMDAwMTkgLTE2LjA0ODYxLC02LjAwOTgxYy0xMC44NDQ4LC0yNC44NDQwMiAtMTYuNDI2ODYsLTUxLjY2NDc3IC0xNi4zOTQ1NCwtNzguNzcyNTljMCwtMjcuOTg4ODggNS44NDY0LC01NC42NDg0OCAxNi4zOTQ1NCwtNzguNzcyNTljMS4zMDY4OCwtMi45OTIxOSAzLjc0OTEzLC01LjM0MjQ2IDYuNzg5MjgsLTYuNTMzNThjMy4wNDAxMiwtMS4xOTExMiA2LjQyODk2LC0xLjEyNTQ2IDkuNDIwNjYsMC4xODI1NHpNMjcxLjM4MDkyLDEzMi4yMzg3MmMtMTEuMjE0NjcsMC4wMDI1MiAtMjEuODIwNDIsNS4xMDE2MiAtMjguODI1ODUsMTMuODU5MDZsLTQuMDM3MSw1LjA0NjM2bC0xLjM2NjIxLC0zLjQzMzk5Yy0zLjczNzYsLTkuMzQwOCAtMTIuNzgzMjIsLTE1LjQ2NzA3IC0yMi44NDQwNiwtMTUuNDcxNDNoLTMuOTc1NTZjLTYuNzk3NjQsMCAtMTIuMzA4MjIsNS41MTA1OCAtMTIuMzA4MjIsMTIuMzA4MjJjMCw2Ljc5NzY0IDUuNTEwNTgsMTIuMzA4MjIgMTIuMzA4MjIsMTIuMzA4MjJoMy45NzU1Nmw2LjU0Nzk3LDE2LjM2OTkybC0xMi43MzksMTUuOTM5MTRjLTIuMzM2ODUsMi45MTg3MyAtNS44NzM3NSw0LjYxNjk5IC05LjYxMjcyLDQuNjE1NTloLTAuNDgwMDJjLTYuNzk3NjQsMCAtMTIuMzA4MjIsNS41MTA1NyAtMTIuMzA4MjIsMTIuMzA4MjJjMCw2Ljc5NzY0IDUuNTEwNTcsMTIuMzA4MjIgMTIuMzA4MjIsMTIuMzA4MjJoMC40ODAwMmMxMS4yMTQ2NywtMC4wMDI1MiAyMS44MjA0MSwtNS4xMDE2MiAyOC44MjU4NSwtMTMuODU5MDZsNC4wMzcxLC01LjA0NjM2bDEuMzY2MjIsMy40MzRjMy43MzkyNiw5LjM0NDk2IDEyLjc5MTA0LDE1LjQ3MjExIDIyLjg1NjM3LDE1LjQ3MTQzaDMuOTc1NTVjNi43OTc2NCwwIDEyLjMwODIyLC01LjUxMDU4IDEyLjMwODIyLC0xMi4zMDgyMmMwLC02Ljc5NzY0IC01LjUxMDU4LC0xMi4zMDgyMiAtMTIuMzA4MjIsLTEyLjMwODIyaC0zLjk3NTU1bC02LjU0Nzk4LC0xNi4zNjk5MmwxMi43MzkwMSwtMTUuOTM5MTNjMi4zMzY4NiwtMi45MTg3MyA1Ljg3Mzc2LC00LjYxNjk4IDkuNjEyNzMsLTQuNjE1NTloMC40ODAwMWM2Ljc5NzY1LDAgMTIuMzA4MjIsLTUuNTEwNTggMTIuMzA4MjIsLTEyLjMwODIyYzAsLTYuNzk3NjQgLTUuNTEwNTcsLTEyLjMwODIyIC0xMi4zMDgyMiwtMTIuMzA4MjJoLTAuNDgwMDF6TTI5NC40NDY1MSwxMDAuMjM3MzdjLTIuNjc2MjMsLTYuMjIxMTEgMC4xNzYxNCwtMTMuNDM1NTMgNi4zODMwNiwtMTYuMTQ0NTFjNi4yMDY5MywtMi43MDg5NyAxMy40MzYyNywwLjEwNTM0IDE2LjE3NzksNi4yOTc5M2MxMC44NDkwMiwyNC44NDMxMSAxNi40MzUzLDUxLjY2MzkxIDE2LjQwNjg2LDc4Ljc3MjZjMCwyNy45ODg4OCAtNS44NDYzOSw1NC42NDg0OCAtMTYuMzk0NTQsNzguNzcyNmMtMS42Njg2Niw0LjE2NTc0IC01LjQ3MjI0LDcuMDkzMTggLTkuOTI2MzMsNy42Mzk4M2MtNC40NTQwOSwwLjU0NjY1IC04Ljg1MjcsLTEuMzc0MTQgLTExLjQ3OTE3LC01LjAxMjczYy0yLjYyNjQ3LC0zLjYzODYxIC0zLjA2NDUsLTguNDE4MjggLTEuMTQzMTUsLTEyLjQ3MzY3YzkuNDg1MzIsLTIxLjczOTA4IDE0LjM2MzQ1LC00NS4yMDc3MSAxNC4zMjY3OCwtNjguOTI2MDFjMCwtMjQuNTMwMjcgLTUuMTIwMjIsLTQ3LjgyOTc0IC0xNC4zMzkwOCwtNjguOTI2MDJ6IiBmaWxsPSIjZmZmZmZmIiBmaWxsLXJ1bGU9ImV2ZW5vZGQiIHN0cm9rZT0ibm9uZSIgc3Ryb2tlLXdpZHRoPSIxIi8+PGcgZmlsbC1ydWxlPSJub256ZXJvIj48cGF0aCBkPSJNMjk1LjEwNTIxLDMwOC45OTEwMmMtMTAuMjYxNjgsMCAtMTguNTgwNDIsLTguMzE4NzMgLTE4LjU4MDQyLC0xOC41ODA0MXYtOTAuNDI0NjdjMCwtMTAuMjYxNjggOC4zMTg3MywtMTguNTgwNDEgMTguNTgwNDIsLTE4LjU4MDQxaDEuMjM4N2MxMC4yNjE2OCwwIDE4LjU4MDQxLDguMzE4NzMgMTguNTgwNDEsMTguNTgwNDF2OTAuNDI0NjdjMCwxMC4yNjE2OCAtOC4zMTg3MywxOC41ODA0MSAtMTguNTgwNDEsMTguNTgwNDF6IiBmaWxsPSIjZmY4YzFhIiBzdHJva2U9IiNmZjhjMWEiIHN0cm9rZS13aWR0aD0iMTIuNSIvPjxwYXRoIGQ9Ik0yMzEuOTMxODIsMjQ0LjU3ODkzYzAsLTEwLjI2MTY4IDguMzE4NzQsLTE4LjU4MDQyIDE4LjU4MDQxLC0xOC41ODA0Mmg5MC40MjQ2NmMxMC4yNjE2OCwwIDE4LjU4MDQsOC4zMTg3MyAxOC41ODA0LDE4LjU4MDQydjEuMjM4N2MwLDEwLjI2MTY5IC04LjMxODcyLDE4LjU4MDQgLTE4LjU4MDQsMTguNTgwNGgtOTAuNDI0NjZjLTEwLjI2MTY3LDAgLTE4LjU4MDQxLC04LjMxODczIC0xOC41ODA0MSwtMTguNTgwNHoiIGZpbGw9IiNmZjhjMWEiIHN0cm9rZT0iI2ZmOGMxYSIgc3Ryb2tlLXdpZHRoPSIxMi41Ii8+PHBhdGggZD0iTTIzOS44ODAxMiwyNDQuNzkwMDZjMCwtNi43NjM1MSA1LjQ4MjkxLC0xMi4yNDY0MSAxMi4yNDY0MiwtMTIuMjQ2NDFoODcuMjk5M2M2Ljc2MzUxLDAgMTIuMjQ2NDIsNS40ODI5IDEyLjI0NjQyLDEyLjI0NjQxdjAuODE2NDVjMCw2Ljc2MzUxIC01LjQ4MjkxLDEyLjI0NjQyIC0xMi4yNDY0MiwxMi4yNDY0MmgtODcuMjk5M2MtNi43NjM1MSwwIC0xMi4yNDY0MiwtNS40ODI5MiAtMTIuMjQ2NDIsLTEyLjI0NjQyeiIgZmlsbD0iI2ZmZmZmZiIgc3Ryb2tlPSIjZmZmZmZmIiBzdHJva2Utd2lkdGg9IjIiLz48cGF0aCBkPSJNMjk2LjE4NDM5LDE4OS4zMDIxOWM2Ljc2MzUxLDAgMTIuMjQ2NDEsNS40ODI5MSAxMi4yNDY0MSwxMi4yNDY0MXY4Ny4yOTkzYzAsNi43NjM1MSAtNS40ODI5LDEyLjI0NjQyIC0xMi4yNDY0MSwxMi4yNDY0MmgtMC44MTY0NWMtNi43NjM1MSwwIC0xMi4yNDY0MiwtNS40ODI5MSAtMTIuMjQ2NDEsLTEyLjI0NjQyYzAsMCAwLC00OS4yMzE5NSAwLC02NC44NjIyN2MwLC04Ljg0ODEzIDAsLTIyLjQzNzA0IDAsLTIyLjQzNzA0YzAsLTYuNzYzNTEgNS40ODI5MSwtMTIuMjQ2NDEgMTIuMjQ2NDIsLTEyLjI0NjQyeiIgZmlsbD0iI2ZmZmZmZiIgc3Ryb2tlPSIjZmZmZmZmIiBzdHJva2Utd2lkdGg9IjIiLz48L2c+PHBhdGggZD0iTTg3LDE4MGMwLC04NC40OTk1NyA2OC41MDA0MywtMTUzIDE1MywtMTUzYzg0LjQ5OTU3LDAgMTUzLDY4LjUwMDQzIDE1MywxNTNjMCw4NC40OTk1NyAtNjguNTAwNDMsMTUzIC0xNTMsMTUzYy04NC40OTk1NywwIC0xNTMsLTY4LjUwMDQzIC0xNTMsLTE1M3oiIGZpbGw9Im5vbmUiIGZpbGwtcnVsZT0ibm9uemVybyIgc3Ryb2tlPSIjZGI2ZTAwIiBzdHJva2Utd2lkdGg9IjE1Ii8+PC9nPjwvZz48L3N2Zz4=";

const xmlEscape = function (unsafe) { return unsafe.replace(/[<>&'"]/g, c => { switch (c) { case "<": return "<"; case ">": return ">"; case "&": return "&"; case "'": return "'"; case "\"": return """; } }); };

function removeAllEventListeners(element) { const clonedElement = element.cloneNode(true); element.parentNode.replaceChild(clonedElement, element); return clonedElement; }

const builtInFonts = [ "Scratch", "Sans Serif", "Serif", "Handwriting", "Marker", "Curly", "Pixel" ];

class MonitorsPlus { constructor() { this.buttonClick = false; this.buttonName = ""; this.monitorsUpdateListeners = []; } getInfo() { return { id: "DICandSPmonitorsPlus", name: "Variables Expanded", color1: "#FF8C1A", color2: "#e67e17", color3: "#cc7015", menuIconURI, blocks: [ { func: "notify", blockType: Scratch.BlockType.BUTTON, text: "Editor Debugging", }, { opcode: "exists", blockType: Scratch.BlockType.BOOLEAN, text: "does [VARIABLE] exist?", arguments: { VARIABLE: { type: Scratch.ArgumentType.STRING, defaultValue: "my variable", }, }, }, { opcode: "isShowing", blockType: Scratch.BlockType.BOOLEAN, text: "is [VARIABLE] showing?", arguments: { VARIABLE: { type: Scratch.ArgumentType.STRING, menu: "variableMenu", }, }, }, "---", { opcode: "setColor", blockType: Scratch.BlockType.COMMAND, text: "set [VARIABLE] to [COLOR]", arguments: { COLOR: { type: Scratch.ArgumentType.COLOR, defaultValue: "#ff0000", }, VARIABLE: { type: Scratch.ArgumentType.STRING, menu: "variableMenu", }, }, }, { opcode: "setString", blockType: Scratch.BlockType.COMMAND, text: "set [VARIABLE] to [STRING]", arguments: { STRING: { type: Scratch.ArgumentType.STRING, defaultValue: 0 }, VARIABLE: { type: Scratch.ArgumentType.STRING, menu: "variableMenu", }, }, }, { opcode: "reportVal", blockType: Scratch.BlockType.REPORTER, text: "value of [VARIABLE]", arguments: { VARIABLE: { type: Scratch.ArgumentType.STRING, menu: "variableMenu", }, }, }, "---", { opcode: "setVariableToType", blockType: Scratch.BlockType.COMMAND, text: "set [VARIABLE] monitor type to [TYPE]", arguments: { VARIABLE: { type: Scratch.ArgumentType.STRING, menu: "variableMenu", }, TYPE: { type: Scratch.ArgumentType.STRING, menu: "variablesTypeMenu", }, }, }, { opcode: "getVariableType", blockType: Scratch.BlockType.REPORTER, text: "monitor type of [VARIABLE]", arguments: { VARIABLE: { type: Scratch.ArgumentType.STRING, menu: "variableMenu", }, }, }, "---", { opcode: "makeVariable", blockType: Scratch.BlockType.COMMAND, text: "create variable named [VARIABLE] [TYPE]", arguments: { VARIABLE: { type: Scratch.ArgumentType.STRING, defaultValue: "my variable 2", }, TYPE: { type: Scratch.ArgumentType.STRING, menu: "variableTypeCreate", defaultValue: "globally", } }, }, { opcode: "deleteVariable", blockType: Scratch.BlockType.COMMAND, text: "delete variable named [VARIABLE]", arguments: { VARIABLE: { type: Scratch.ArgumentType.STRING, defaultValue: "my variable 2", } }, }, { blockType: Scratch.BlockType.XML, xml: "<sep gap=\"6\"/><label text=\"Sliders\"/><sep gap=\"-12\"/><sep gap=\"12\"/>", }, { opcode: "setSliderMinMaxOfVaribleTo", blockType: Scratch.BlockType.COMMAND, text: "set slider min [MIN] and max [MAX] of [VARIABLE]", arguments: { MIN: { type: Scratch.ArgumentType.NUMBER, defaultValue: -100, }, MAX: { type: Scratch.ArgumentType.NUMBER, defaultValue: 100, }, VARIABLE: { type: Scratch.ArgumentType.STRING, menu: "variableMenu", }, }, }, { opcode: "sliderMinMaxOfVarible", blockType: Scratch.BlockType.REPORTER, text: "slider [MINMAX] of [VARIABLE]", arguments: { MINMAX: { type: Scratch.ArgumentType.STRING, menu: "sliderMaxMinMenu", }, VARIABLE: { type: Scratch.ArgumentType.STRING, menu: "variableMenu", }, }, }, { blockType: Scratch.BlockType.XML, xml: "<sep gap=\"6\"/><label text=\"Positioning\"/><sep gap=\"-12\"/><sep gap=\"12\"/>", }, { opcode: "setPosition", blockType: Scratch.BlockType.COMMAND, text: "set position of [VARIABLE] to x: [X] y: [Y]", arguments: { X: { type: Scratch.ArgumentType.NUMBER, defaultValue: 0, }, Y: { type: Scratch.ArgumentType.NUMBER, defaultValue: 0, }, VARIABLE: { type: Scratch.ArgumentType.STRING, menu: "variableMenu", }, }, }, { opcode: "currentPos", blockType: Scratch.BlockType.REPORTER, text: "current [POSITION] of [VARIABLE]", arguments: { VARIABLE: { type: Scratch.ArgumentType.STRING, menu: "variableMenu", }, POSITION: { type: Scratch.ArgumentType.STRING, menu: "POSITIONS", defaultValue: "x", }, }, }, { blockType: Scratch.BlockType.XML, xml: "<sep gap=\"6\"/><label text=\"Buttons\"/><sep gap=\"-12\"/><sep gap=\"12\"/>", }, { opcode: "whenButtonPressed", blockType: Scratch.BlockType.HAT, text: "when [VARIABLE] button pressed", arguments: { VARIABLE: { type: Scratch.ArgumentType.STRING, menu: "variableMenu", }, }, }, { opcode: "isButtonPressed", blockType: Scratch.BlockType.BOOLEAN, text: "is [VARIABLE] button pressed?", disableMonitor: true, arguments: { VARIABLE: { type: Scratch.ArgumentType.STRING, menu: "variableMenu", }, }, }, { blockType: Scratch.BlockType.XML, xml: "<sep gap=\"6\"/><label text=\"Effects\"/><sep gap=\"-12\"/><sep gap=\"12\"/>", }, { opcode: "setDisplay", blockType: Scratch.BlockType.COMMAND, text: "set display name of [VARIABLE] to [NAME]", arguments: { NAME: { type: Scratch.ArgumentType.STRING, defaultValue: "my cooler variable", }, VARIABLE: { type: Scratch.ArgumentType.STRING, menu: "variableMenu", }, }, }, { opcode: "setFont", blockType: Scratch.BlockType.COMMAND, text: "set font of [VARIABLE] to [FONT]", arguments: { FONT: { type: Scratch.ArgumentType.STRING, menu: "allFonts", defaultValue: "Scratch", }, VARIABLE: { type: Scratch.ArgumentType.STRING, menu: "variableMenu", }, }, }, "---", { opcode: "resetEffect", blockType: Scratch.BlockType.COMMAND, text: "reset effects of [VARIABLE]", arguments: { VARIABLE: { type: Scratch.ArgumentType.STRING, menu: "variableMenu", }, }, }, { opcode: "setEffect", blockType: Scratch.BlockType.COMMAND, text: "set [EFFECT] of [VARIABLE] to [AMOUNT]", arguments: { AMOUNT: { type: Scratch.ArgumentType.NUMBER, defaultValue: 5, }, EFFECT: { type: Scratch.ArgumentType.STRING, menu: "EFFECTS", defaultValue: "blur", }, VARIABLE: { type: Scratch.ArgumentType.STRING, menu: "variableMenu", }, }, }, { opcode: "currentEffect", blockType: Scratch.BlockType.REPORTER, text: "current [EFFECT] of [VARIABLE]", arguments: { VARIABLE: { type: Scratch.ArgumentType.STRING, menu: "variableMenu", }, EFFECT: { type: Scratch.ArgumentType.STRING, menu: "EFFECTS", defaultValue: "blur", }, }, }, ], menus: { variablesTypeMenu: { acceptReporters: true, items: [ "normal readout", "large readout", "slider", "text", "checkbox", "color", "button", "file", "image", "audio" ], }, sliderMaxMinMenu: ["min", "max"], variableMenu: { acceptReporters: true, items: "getVariables", }, allFonts: { acceptReporters: true, items: "getFonts", }, variableTypeCreate: ["globally", "for this sprite only"], POSITIONS: ["x", "y"], EFFECTS: { acceptReporters: true, items: [ "blur", "saturation", "contrast", "brightness", "hue", "opacity", "sepia", "invert", "direction", "scale", "skew x", "skew y" ], }, } } }

notify() {
  alert(
    "Upon Double-Clicking New Monitors, it will open up the Debug Menu" +
    "\n\nThis feature is only accessible within the Editor and can be reset by using the set monitor block"
  );
}

getVariables() {
  const globalVars = Object.values(vm.runtime.getTargetForStage().variables).filter((x) => x.type == "");
  const localVars = Object.values(vm.editingTarget.variables).filter((x) => x.type == "");
  const uniqueVars = [...new Set([...globalVars, ...localVars])];
  if (uniqueVars.length === 0) return ["make a variable"];
  return uniqueVars.map((i) => (Scratch.Cast.toString(i.name)));
}

getFonts() {
  const customFonts = Scratch.vm.runtime.fontManager ? Scratch.vm.runtime.fontManager.getFonts().map((i) => ({text: i.name, value: i.family})) : [];
  return [
    ...builtInFonts,
    ...customFonts,
  ];
}

findVariable(variable, sprite) {
  //support for all variable types
  const cloudID = runtime.getTargetForStage().lookupVariableByNameAndType(Scratch.Cast.toString("☁ " + variable), "");
  if (cloudID) return cloudID.id;
  let varFind = "";
  for (const name of Object.getOwnPropertyNames(sprite.target.variables)) {
    varFind = sprite.target.variables[name].name;
    if (varFind === variable) return sprite.target.variables[name].id;
  }
  const ID = runtime.getTargetForStage().lookupVariableByNameAndType(variable, "");
  if (!ID) return "";
  return ID.id;
}

resetFormat(variableId) {
  runtime.requestUpdateMonitor(new Map([
    ["id", variableId],
    ["visible", false]
  ]));
  setTimeout(() => {
    runtime.requestUpdateMonitor(new Map([
      ["id", variableId],
      ["visible", true]
    ]));
  }, 30);
}

async setVariableToType(args, util) { await this.setMonitor(args.VARIABLE, util, args.VARIABLE, args.TYPE) }

async setDisplay(args, util) {
  const safeName = xmlEscape(args.NAME);
  const type = this.getMonitor(args.VARIABLE, util);
  let variableId = this.findVariable(args.VARIABLE, util);
  if (type.includes("readout") || type === "slider") {
    const variableMonitorLabel = document.querySelector(`[data-id="${variableId}"][class*="monitor"] [class^="monitor_label"]`);
    if (variableMonitorLabel) variableMonitorLabel.textContent = args.NAME;
  } else {
    await this.setMonitor(args.VARIABLE, util, args.NAME, type);
  }
}

async setMonitor(nameID, util, name, type) {
  let variableId = this.findVariable(nameID, util);
  const oldStyle = document.querySelector(`[data-id="${variableId}"][class*="monitor"]`);
  if (type.includes("readout") || type === "slider") {
    if (!(this.getMonitor(nameID, util).includes("readout") || this.getMonitor(nameID, util) === "slider")) {
      this.resetFormat(variableId);
    }
  }
  if (!type.includes("readout") && type !== "slider") {
    var state2 = vm.runtime.getMonitorState().get(variableId);
    vm.runtime.requestUpdateMonitor(state2.set("mode", "default"));
    let i;
    await new Promise(resolve => { const wait = () => {
      if (i) resolve();
      else {
        i = runtime.getMonitorState().get(variableId).get("visible");
        setTimeout(wait, 5);
      }};
      wait();
    });
  }

  const variableMonitor = document.querySelector(`[data-id="${variableId}"][class*="monitor"]`);
  if (!variableMonitor) return;
  let typeElement;
  let isHex;
  let variableName = nameID;
  let toggleButtonClickFunction;
  let container;

  const hexColorRegex = /^#([0-9A-F]{3}){1,2}$/i;
  const Vvalue = util.target.lookupOrCreateVariable(nameID, variableName).value;
  const isChecked = Vvalue === "true" || Vvalue === 1 ? true : false;
  variableName = name.replace(/[<>]/g, "");
  this.removeAllMonitorsUpdateListeners();
  if (type.includes("readout") || type === "slider") {
    var state = vm.runtime.getMonitorState().get(variableId);
    vm.runtime.requestUpdateMonitor(state.set("mode", "large"));
  } else {
    let oldMonitor = variableMonitor.querySelector(`[class^="monitor_default-monitor"]:not(.monitor_default-monitor_SPnew1)`);
    if (!oldMonitor) oldMonitor = variableMonitor.querySelector(`[class^="sc-monitor-inner"] [class^="sc-monitor-row"]`);
    oldMonitor.style.display = "none";
  }

  switch (type) {
    case "large readout":
      state = state.set("mode", "large");
      vm.runtime.requestUpdateMonitor(state);
      break;
    case "slider":
      state = state.set("mode", "slider");
      vm.runtime.requestUpdateMonitor(state);
      break;
    case "text":
      if (variableMonitor.querySelector(`[class^="monitor_default-monitor_SPnew1"`)) {
        container = variableMonitor.querySelector(`[class^="monitor_default-monitor_SPnew1"`);
      } else {
        container = document.createElement("div");
        container.className = "monitor_default-monitor_SPnew1";
        container.setAttribute("style", "padding: 5px 5px 5px 5px");
      }
      container.innerHTML = `
        <div class="monitor_row_2y_kM">
          <div class="monitor_label_ci1ok">${variableName}</div>
        </div>
        <div class="monitor_row_2y_kM">
          <input type="text" id="text_${variableId}" class="monitor_slider_1CHwk no-drag" value="${Vvalue}">
        </div>`;
      variableMonitor.appendChild(container);
      typeElement = container.querySelector(`[id="text_${variableId}"]`);
      typeElement = removeAllEventListeners(typeElement);

      this.addMonitorsUpdateListener(() => {
        const variable = util.target.lookupOrCreateVariable(nameID, nameID);
        typeElement.value = variable.value;
      });
      typeElement.addEventListener("change", function (event) {
        if (event.target && event.target.id.startsWith(`text_${variableId}`)) {
          const variable = util.target.lookupOrCreateVariable(nameID, nameID);
          variable.value = typeElement.value;
        }
      });
      break;
    case "checkbox":
      if (variableMonitor.querySelector(`[class^="monitor_default-monitor_SPnew1"]`)) {
        container = variableMonitor.querySelector(`[class^="monitor_default-monitor_SPnew1"]`);
      } else {
        container = document.createElement("div");
        container.className = "monitor_default-monitor_SPnew1";
        container.setAttribute("style", "padding: 5px 5px 5px 5px");
      }
      container.innerHTML = `
        <div class="monitor_row_2y_kM">
          <input type="checkbox" id="checkbox_${variableId}" class="monitor_slider_1CHwk no-drag" ${isChecked ? "checked" : ""}>
          <div class="monitor_label_ci1ok">${variableName}</div>
        </div>`;
      variableMonitor.appendChild(container);
      typeElement = container.querySelector(`[id="checkbox_${variableId}"`);
      typeElement = removeAllEventListeners(typeElement);

      this.addMonitorsUpdateListener(() => {
        const variable = util.target.lookupOrCreateVariable(nameID, nameID);
        typeElement.checked = variable.value === "false" ? 0 : variable.value;
      });
      typeElement.addEventListener("change", function (event) {
        if (event.target && event.target.id.startsWith(`checkbox_${variableId}`)) {
          const variable = util.target.lookupOrCreateVariable(nameID, nameID);
          variable.value = typeElement.checked;
        }
      });
      break;
    case "color":
      if (hexColorRegex.test(Vvalue)) {
        isHex = Vvalue;
      } else {
        isHex = "#ff0000";
      }
      if (variableMonitor.querySelector(`[class^="monitor_default-monitor_SPnew1"]`)) {
        container = variableMonitor.querySelector(`[class^="monitor_default-monitor_SPnew1"]`);
      } else {
        container = document.createElement("div");
        container.className = "monitor_default-monitor_SPnew1";
        container.setAttribute("style", "padding: 5px 5px 5px 5px");
      }

      container.innerHTML = `
        <div class="monitor_row_2y_kM">
          <div class="monitor_label_ci1ok">${variableName}</div>
        </div>
        <div class="monitor_row_2y_kM">
          <input type="color" id="color_${variableId}" class="monitor_slider_1CHwk no-drag" value="${isHex}">
        </div>`;
      variableMonitor.appendChild(container);
      typeElement = container.querySelector(`[id="color_${variableId}"`);
      typeElement = removeAllEventListeners(typeElement);

      this.addMonitorsUpdateListener(() => {
        const variable = util.target.lookupOrCreateVariable(nameID, nameID);
        typeElement.value = variable.value;
      });
      typeElement.addEventListener("change", function (event) {
        if (event.target && event.target.id.startsWith(`color_${variableId}`)) {
          const variable = util.target.lookupOrCreateVariable(nameID, nameID);
          variable.value = typeElement.value;
        }
      });
      break;
    case "button":
      if (variableMonitor.querySelector(`[class^="monitor_default-monitor_SPnew1"]`)) {
        container = variableMonitor.querySelector(`[class^="monitor_default-monitor_SPnew1"]`);
      } else {
        container = document.createElement("div");
        container.className = "monitor_default-monitor_SPnew1";
        container.setAttribute("style", "padding: 5px 5px 5px 5px");
      }
      container.innerHTML = `
        <div class="monitor_row_2y_kM">
          <input type="button" id="button_${variableId}" value="${variableName}" class="monitor_slider_1CHwk no-drag monitor-button">
        </div>`;
      variableMonitor.appendChild(container);
      typeElement = container.querySelector(`[id="button_${variableId}"]`);
      toggleButtonClickFunction = () => this.toggleButtonClick(variableId);
      typeElement.onclick = toggleButtonClickFunction;
      typeElement.addEventListener("click", toggleButtonClickFunction);
      break;
    case "file":
      if (variableMonitor.querySelector(`[class^="monitor_default-monitor_SPnew1"]`)) {
        container = variableMonitor.querySelector(`[class^="monitor_default-monitor_SPnew1"]`);
      } else {
        container = document.createElement("div");
        container.className = "monitor_default-monitor_SPnew1";
        container.setAttribute("style", "padding: 5px 5px 5px 5px");
      }
      container.innerHTML = `
        <div class="monitor_row_2y_kM">
          <div class="monitor_label_ci1ok">${variableName}</div>
        </div>
        <div class="monitor_row_2y_kM">
          <input type="file" id="file_${variableId}" class="monitor_slider_1CHwk no-drag" value="0">
        </div>`;
      variableMonitor.appendChild(container);

      typeElement = container.querySelector(`[id="file_${variableId}"]`);
      typeElement = removeAllEventListeners(typeElement);
      typeElement.addEventListener("change", function (event) {
        if (event.target && event.target.id === `file_${variableId}`) {
          const file = event.target.files[0];
          if (file) {
            const reader = new FileReader();
            reader.readAsDataURL(file);
            reader.onload = function () {
              const variable = util.target.lookupOrCreateVariable(nameID, variableName);
              variable.value = reader.result;
            };
            reader.onerror = function (error) {
              console.log("Error: ", error);
            };
          }
        }
      });
      break;
    case "image":
      if (variableMonitor.querySelector(`[class^="monitor_default-monitor_SPnew1"]`)) {
        container = variableMonitor.querySelector(`[class^="monitor_default-monitor_SPnew1"]`);
      } else {
        container = document.createElement("div");
        container.className = "monitor_default-monitor_SPnew1";
        container.setAttribute("style", "padding: 5px 5px 5px 5px");
      }
      container.innerHTML = `
        <div class="monitor_row_2y_kM">
          <div class="monitor_label_ci1ok">${variableName}</div>
        </div>
        <div class "monitor_row_2y_kM">
          <img src="${Vvalue}" id="image_${variableId}" class="monitor_slider_1CHwk no-drag">
        </div>`;
      variableMonitor.appendChild(container);
      typeElement = container.querySelector(`[id="image_${variableId}"]`);
      this.addMonitorsUpdateListener(() => {
        const variable = util.target.lookupOrCreateVariable(nameID, nameID);
        typeElement.src = variable.value;
      });
      break;
    case "audio":
      if (variableMonitor.querySelector(`[class^="monitor_default-monitor_SPnew1"]`)) {
        container = variableMonitor.querySelector(`[class^="monitor_default-monitor_SPnew1"]`);
      } else {
        container = document.createElement("div");
        container.className = "monitor_default-monitor_SPnew1";
        container.setAttribute("style", "padding: 5px 5px 5px 5px");
      }
      container.innerHTML = `
        <div class="monitor_row_2y_kM">
          <div class="monitor_label_ci1ok">${variableName}</div>
        </div>
        <div class="monitor_row_2y_kM">
          <audio id="audio_${variableId}" class="monitor_audio" src="${Vvalue}" controls></audio>
        </div>`;
      variableMonitor.appendChild(container);

      typeElement = container.querySelector(`[id="audio_${variableId}"]`);
      this.addMonitorsUpdateListener(() => {
        const variable = util.target.lookupOrCreateVariable(nameID, nameID);
        typeElement.src = variable.value;
      });
      break;
    default: // Handle unknown monitor or default monitor
      state = state.set("mode", "default");
      vm.runtime.requestUpdateMonitor(state);
      break;
  }
  this.reAddDeleted(oldStyle, variableId, nameID, util);
}

addMonitorsUpdateListener(listener) {
  runtime.on("MONITORS_UPDATE", listener);
  this.monitorsUpdateListeners.push(listener);
}
removeAllMonitorsUpdateListeners() {
  for (const listener of this.monitorsUpdateListeners) {
    runtime.removeListener("MONITORS_UPDATE", listener);
  }
  this.monitorsUpdateListeners.length = 0;
}

toggleButtonClick(ID) {
  this.buttonName = ID;
  this.buttonClick = true;
  setTimeout(() => {
    this.buttonClick = false;
    this.buttonName = "";
  }, 100);
}

isButtonPressed(args, util) {
  const variableId = this.findVariable(args.VARIABLE, util);
  if (!variableId) return false;
  return variableId === this.buttonName ? !!this.buttonClick : false;
}

whenButtonPressed(args, util) {
  const variableId = this.findVariable(args.VARIABLE, util);
  if (!variableId) return false;
  return variableId === this.buttonName ? !!this.buttonClick : false;
}

getVariableType(args, util) { return this.getMonitor(args.VARIABLE, util) }

getMonitor(variable, util) {
  const variableId = this.findVariable(variable, util);
  const variableMonitor = document.querySelector(`[data-id="${variableId}"][class*="monitor"]`);
  if (!variableMonitor) return "normal readout";
  if (variableMonitor.querySelector("input[type=\"range\"]")) return "slider";
  if (variableMonitor.querySelector("input[type=\"text\"]")) return "text";
  if (variableMonitor.querySelector("input[type=\"checkbox\"]")) return "checkbox";
  if (variableMonitor.querySelector("input[type=\"color\"]")) return "color";
  if (variableMonitor.querySelector("input[type=\"button\"]")) return "button";
  if (variableMonitor.querySelector("input[type=\"file\"]")) return "file";
  if (variableMonitor.querySelector("img")) return "image";
  if (variableMonitor.querySelector("audio")) return "audio";
  if (variableMonitor.querySelector(`[class^="monitor_large-value_"]`)) return "large readout";
  return "normal readout";
}

setSliderMinMaxOfVaribleTo(args, util) {
  const variableId = this.findVariable(args.VARIABLE, util);
  if (!(this.getMonitor(args.VARIABLE, util).includes("readout") || this.getMonitor(args.VARIABLE, util) === "slider")) {
    this.resetFormat(variableId);
  }
  var state = vm.runtime.getMonitorState().get(variableId);
  if (!state) return "";
  state = state.set("mode", "slider");
  runtime.requestUpdateMonitor(state);
  runtime.requestUpdateMonitor(new Map([
    ["id", variableId],
    ["sliderMin", args.MIN],
    ["sliderMax", args.MAX]
  ]));
}

sliderMinMaxOfVarible(args, util) {
  const variableId = this.findVariable(args.VARIABLE, util);
  const info = vm.runtime.getMonitorState().get(variableId);
  if (info === undefined) return "";
  return info.get(args.MINMAX === "min" ? "sliderMin" : "sliderMax");
}

setColor(args, util) { this.setValue(args.VARIABLE, args.COLOR, util) }
setString(args, util) { this.setValue(args.VARIABLE, args.STRING, util) }

setValue(variableN, value, util) {
  const variableName = variableN; 
  const variable = util.target.lookupOrCreateVariable(variableN, variableName);
  variable.value = value;
}

reportVal(args, util) {
  const variableId = this.findVariable(args.VARIABLE, util);
  if (!variableId) return 0;
  const variable = util.target.lookupVariableById(variableId);
  return variable.value;
}

isShowing(args, util) {
  const variableId = this.findVariable(args.VARIABLE, util);
  const info = runtime.getMonitorState().get(variableId);
  return info ? (info.get("visible") !== undefined && info.get("visible") !== false) : false;
}
exists(args, util) {
  const variableId = this.findVariable(args.VARIABLE, util);
  return Scratch.Cast.toBoolean(variableId);
}

setPosition(args, util) {
  const canvas = [Scratch.vm.runtime.stageWidth / 2, Scratch.vm.runtime.stageHeight / 2];
  const variableId = this.findVariable(args.VARIABLE, util);
  const variableMonitor = document.querySelector(`[data-id="${variableId}"][class*="monitor"]`);
  if (!variableMonitor) return;
  let x = Scratch.Cast.toNumber(args.X) + canvas[0] - (variableMonitor.offsetWidth / 2);
  let y = (Scratch.Cast.toNumber(args.Y) - canvas[1] + (variableMonitor.offsetHeight / 2)) * -1;
  x = x - (parseInt(variableMonitor.style.left) || 5);
  y = y - (parseInt(variableMonitor.style.top) || 5);

  let styleAttribute = variableMonitor.getAttribute("style");
  const transformRegex = /transform:([^;]+);/;
  const transformMatch = styleAttribute.match(transformRegex);

  if (transformMatch) {
    const existingTransform = transformMatch[1];
    const updatedTransform = existingTransform.replace(/translate\([^)]+\)/, `translate(${x}px, ${y}px)`);
    styleAttribute = styleAttribute.replace(transformRegex, `transform:${updatedTransform};`);
    variableMonitor.setAttribute("style", styleAttribute);
  }
}

currentPos(args, util) {
  const canvas = [Scratch.vm.runtime.stageWidth / 2, Scratch.vm.runtime.stageHeight / 2];
  const variableId = this.findVariable(args.VARIABLE, util);
  const variableMonitor = document.querySelector(`[data-id="${variableId}"][class*="monitor"]`);
  if (!variableMonitor) return "";

  const styleAttribute = variableMonitor.getAttribute("style");
  if (styleAttribute) {
    const match = styleAttribute.match(/transform\s*:\s*translate\((-?\d+(?:\.\d+)?px),\s*(-?\d+(?:\.\d+)?px)\)/);
    if (match) {
      if (args.POSITION === "x") {
        return Math.round(parseInt(match[1]) - canvas[0] + (variableMonitor.offsetWidth / 2)) + parseInt(variableMonitor.style.left);
      } else {
        return Math.round(((parseInt(match[2]) * -1) + canvas[1]) - (variableMonitor.offsetHeight / 2) - parseInt(variableMonitor.style.top)) - 1;
      }
    }
  }
  return "";
}

resetEffects(variableId, currentTransform) {
  const variableMonitor = document.querySelector(`[data-id="${variableId}"][class*="monitor"]`);
  if (!variableMonitor) return;
  const translationRegex = /translate\(([^,]+),\s*([^)]+)\)/;
  const matches = currentTransform.match(translationRegex);
  const translation = matches ? `translate(${matches[1]}, ${matches[2]})` : "";
  variableMonitor.style.filter = "";
  variableMonitor.style.transform = translation;
}

setEffect(args, util) { this.varEffect(args.VARIABLE, args.EFFECT, args.AMOUNT, util) }

varEffect(VARIABLE, EFFECT, AMOUNT, util) {
  const variableId = this.findVariable(VARIABLE, util);
  const variableMonitor = document.querySelector(`[data-id="${variableId}"][class*="monitor"]`);
  if (!variableMonitor) return;
  let currentTransform = variableMonitor.style.transform;
  let currentFilterEffect = variableMonitor.style.filter || "";
  let setEffect = EFFECT;
  let amountIn = AMOUNT;

  if (setEffect === "saturation") {
    setEffect = "saturate";
  } else if (setEffect === "hue") {
    setEffect = "hue-rotate";
  } else if (setEffect === "direction") {
    setEffect = "rotate";
    amountIn = AMOUNT - 90;
  } else if (setEffect === "scale") {
    amountIn = AMOUNT / 100;
  } else if (setEffect === "brightness") {
    amountIn = AMOUNT + 100;
  } else if (setEffect === "skew x") {
    setEffect = "skewX";
  } else if (setEffect === "skew y") {
    setEffect = "skewY";
  }
  const regex = new RegExp(`${setEffect}\\([^)]+\\)`, "g");
  currentTransform = currentTransform.replace(regex, "").trim();
  currentFilterEffect = currentFilterEffect.replace(regex, "").trim();

  if (setEffect === "scale" || setEffect === "rotate" || setEffect.includes("skew")) {
    currentTransform += ` ${setEffect}(${amountIn}${setEffect === "rotate" || setEffect.includes("skew") ? "deg" : ""})`;
    variableMonitor.style.transform = currentTransform.trim();
  } else {
    currentFilterEffect += ` ${setEffect}(${amountIn}${setEffect === "blur" ? "px" : setEffect === "hue-rotate" ? "deg" : "%"})`;
    variableMonitor.style.filter = currentFilterEffect.trim();
  }
}

currentEffect(args, util) {
  const variableId = this.findVariable(args.VARIABLE, util);
  const variableMonitor = document.querySelector(`[data-id="${variableId}"][class*="monitor"]`);
  if (!variableMonitor) return "";
  const currentTransform = variableMonitor.style.transform;
  const currentFilterEffect = variableMonitor.style.filter || "";
  const setEffect = {
    saturation: "saturate",
    hue: "hue-rotate",
    direction: "rotate",
    scale: "scale",
    brightness: "brightness",
    opacity: "opacity",
    "skew x": "skewX",
    "skew y": "skewY",
  }[args.EFFECT] || args.EFFECT;
  const defaultV = {
    saturation: 100,
    hue: 0,
    direction: 90,
    scale: 100,
    brightness: 0,
    opacity: 100,
  }[args.EFFECT] || 0;

  const regex = new RegExp(`${setEffect}\\(([^)]+)\\)`);
  const transformMatch = currentTransform.match(regex);
  const filterMatch = currentFilterEffect.match(regex);

  if (filterMatch || transformMatch) {
    const valueWithUnits = (filterMatch || transformMatch)[1];
    const numericValue = parseFloat(valueWithUnits.replace(/[^0-9.-]/g, ""));
    if (setEffect === "brightness") {
      return numericValue - 100;
    } else if (setEffect === "rotate") {
      return numericValue + 90;
    } else if (setEffect === "scale") {
      return numericValue * 100;
    } else {
      return numericValue;
    }
  } else {
    return defaultV;
  }
}

resetEffect(args, util) {
  const variableId = this.findVariable(args.VARIABLE, util);
  const variableMonitor = document.querySelector(`[data-id="${variableId}"][class*="monitor"]`);
  if (!variableMonitor) return;
  let currentTransform = variableMonitor.style.transform || "";
  this.resetEffects(variableId, currentTransform);
}

setFont(args, util) {
  const variableId = this.findVariable(args.VARIABLE, util);
  const variableMonitor = document.querySelector(`[data-id="${variableId}"][class*="monitor"]`);
  if (!variableMonitor) return;
  variableMonitor.style.fontFamily = args.FONT;
}

makeVariable(args, util) {
  if (args.TYPE === "for this sprite only") {
    return util.target.lookupOrCreateVariable(this.generateId(), args.VARIABLE, "");
  } else {
    return runtime.createNewGlobalVariable(args.VARIABLE, "");
  }
}

deleteVariable(args, util) {
  const variableId = this.findVariable(args.VARIABLE, util);
  if (variableId) {
    runtime.getTargetForStage().deleteVariable(variableId)
    util.target.deleteVariable(variableId);
  }
}

generateId() {
  const chars = ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "/", "|", ",", ".", "{", "}", "[", "]", "(", ")", "+", "-", "!", "?", "`"];
  const array = Array.from(Array(20).keys());
  const normalArray = array.map(() => {
    return chars[Math.round(Math.random() * (chars.length - 1))]
  })
  return normalArray.join("");
}

reAddDeleted(variable, id, name, util) {
  const waitAndExecute = () => {
    if (!this.isShowing({VARIABLE : name}, util)) {
      setTimeout(waitAndExecute, 5);
      return;
    }
    setTimeout(() => {
      const variableMonitor = document.querySelector(`[data-id="${id}"][class*="monitor"]`);
      const inlineStyles = variable.getAttribute("style");
      if (variableMonitor.style) variableMonitor.style = inlineStyles;
    }, 10);
  };
  waitAndExecute();
}

}

Scratch.extensions.register(new MonitorsPlus()); })(Scratch);

Bluecube5997thefan commented 6 months ago

=

@softedco, Have you tried the extension? It makes an actual new variable:

image

There we go ![Uploading block_2_18_2024-9_10_05 PM.png…]()

The-Best-Codes commented 3 weeks ago

Thank you guys for all the feedback. I'm gonna close this now.