diff --git a/actions/canvas_create_primitive_MOD.js b/actions/canvas_create_primitive_MOD.js
index ebb0db46..eee55c92 100644
--- a/actions/canvas_create_primitive_MOD.js
+++ b/actions/canvas_create_primitive_MOD.js
@@ -11,13 +11,24 @@ module.exports = {
subtitle(data) {
const info = parseInt(data.info, 10);
- if (info === 0) {
- return data.color ? `Create Circle with Color ${data.color}` : 'No color circle has been created';
- }
- if (info === 1) {
- return data.color ? `Create Rectangle with Color ${data.color}` : 'No color rectangle has been created';
+ switch (info) {
+ case 0:
+ return data.color ? `Create Circle with Color ${data.color}` : 'No color circle has been created';
+ case 1:
+ return data.color ? `Create Rectangle with Color ${data.color}` : 'No color rectangle has been created';
+ case 2:
+ return data.color ? `Create Triangle with Color ${data.color}` : 'No color triangle has been created';
+ case 3:
+ return data.color ? `Create Hexagon with Color ${data.color}` : 'No color hexagon has been created';
+ case 4:
+ return data.color ? `Create Pentagon with Color ${data.color}` : 'No color pentagon has been created';
+ case 5:
+ return data.color ? `Create Ellipse with Color ${data.color}` : 'No color ellipse has been created';
+ case 6:
+ return data.color ? `Create Star with Color ${data.color}` : 'No color star has been created';
+ default:
+ return '';
}
- // Add more cases for different shapes as needed
},
variableStorage(data, varType) {
@@ -35,12 +46,15 @@ module.exports = {
Circle
Rectangle
-
+ Triangle
+ Hexagon
+ Pentagon
+ Ellipse
+ Star
-
Width (px)
@@ -52,7 +66,6 @@ module.exports = {
-
Color
@@ -60,7 +73,6 @@ module.exports = {
-
`;
},
@@ -75,18 +87,93 @@ module.exports = {
const ctx = canvas.getContext('2d');
const color = this.evalMessage(data.color, cache);
+ let sideLength;
+ let xCenter;
+ let yCenter;
+ let angle;
+ let x;
+ let y;
+ let angleStep;
+ let radius;
+ let centerX;
+ let centerY;
+ let numPoints;
+ let outerRadius;
+ let innerRadius;
+
switch (shapeType) {
- case 0: // Circle
+ case 0:
ctx.beginPath();
ctx.arc(width / 2, height / 2, Math.min(width, height) / 2, 0, 2 * Math.PI);
ctx.fillStyle = color;
ctx.fill();
break;
- case 1: // Rectangle
+ case 1:
ctx.fillStyle = color;
ctx.fillRect(0, 0, width, height);
break;
- // Add more cases for different shapes
+ case 2:
+ ctx.beginPath();
+ ctx.moveTo(width / 2, 0);
+ ctx.lineTo(width, height);
+ ctx.lineTo(0, height);
+ ctx.closePath();
+ ctx.fillStyle = color;
+ ctx.fill();
+ break;
+ case 3:
+ ctx.beginPath();
+ sideLength = Math.min(width, height) / 2;
+ xCenter = width / 2;
+ yCenter = height / 2;
+ for (let i = 0; i < 6; i++) {
+ angle = (Math.PI / 3) * i;
+ x = xCenter + sideLength * Math.cos(angle);
+ y = yCenter + sideLength * Math.sin(angle);
+ if (i === 0) {
+ ctx.moveTo(x, y);
+ } else {
+ ctx.lineTo(x, y);
+ }
+ }
+ ctx.closePath();
+ ctx.fillStyle = color;
+ ctx.fill();
+ break;
+ case 4:
+ ctx.beginPath();
+ angleStep = (2 * Math.PI) / 5;
+ radius = Math.min(width, height) / 2;
+ centerX = width / 2;
+ centerY = height / 2;
+ ctx.moveTo(centerX + radius * Math.cos(0), centerY + radius * Math.sin(0));
+ for (let i = 1; i <= 5; i++) {
+ ctx.lineTo(centerX + radius * Math.cos(angleStep * i), centerY + radius * Math.sin(angleStep * i));
+ }
+ ctx.closePath();
+ ctx.fillStyle = color;
+ ctx.fill();
+ break;
+ case 5:
+ ctx.beginPath();
+ ctx.ellipse(width / 2, height / 2, width / 2, height / 2, 0, 0, 2 * Math.PI);
+ ctx.fillStyle = color;
+ ctx.fill();
+ break;
+ case 6:
+ numPoints = 5;
+ outerRadius = Math.min(width, height) / 2;
+ innerRadius = outerRadius * 0.5;
+ ctx.beginPath();
+ for (let i = 0; i < numPoints * 2; i++) {
+ const radius = i % 2 === 0 ? outerRadius : innerRadius;
+ const angle = (i * Math.PI) / numPoints - Math.PI / 2;
+ ctx.lineTo(width / 2 + radius * Math.cos(angle), height / 2 + radius * Math.sin(angle));
+ }
+ ctx.closePath();
+ ctx.fillStyle = color;
+ ctx.fill();
+ break;
default:
break;
}
diff --git a/actions/json_random_MOD.js b/actions/json_random_MOD.js
new file mode 100644
index 00000000..38587f8e
--- /dev/null
+++ b/actions/json_random_MOD.js
@@ -0,0 +1,99 @@
+const fs = require('fs');
+const path = require('path');
+
+module.exports = {
+ name: 'Pick Random JSON Item',
+ section: 'File Stuff',
+ fields: ['filepath', 'title', 'storage', 'varName'],
+
+ subtitle(data) {
+ return `Pick random item from JSON file "${data.filepath}"`;
+ },
+
+ variableStorage(data, varType) {
+ if (parseInt(data.storage, 10) !== varType) return;
+ return [data.varName, 'Text'];
+ },
+
+ html() {
+ return `
+
+
+ File Path
+
+
+
+ Title
+
+
+
+
+
+
+ `;
+ },
+
+ init() {},
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ let filepath = this.evalMessage(data.filepath, cache);
+ const title = this.evalMessage(data.title, cache);
+ const storage = parseInt(data.storage, 10);
+ const varName = this.evalMessage(data.varName, cache);
+
+ if (filepath.startsWith('./')) {
+ filepath = path.join(__dirname, '..', filepath.substring(2));
+ }
+
+ let jsonData;
+
+ try {
+ if (fs.existsSync(filepath)) {
+ const fileData = fs.readFileSync(filepath);
+ if (fileData.length === 0) {
+ console.warn('JSON file is empty.');
+ this.storeValue(undefined, storage, varName, cache);
+ return this.callNextAction(cache);
+ }
+ jsonData = JSON.parse(fileData);
+ } else {
+ throw new Error('File does not exist');
+ }
+ } catch (error) {
+ console.error(`Error reading JSON file: ${error}`);
+ this.storeValue(undefined, storage, varName, cache);
+ return this.callNextAction(cache);
+ }
+
+ let result;
+
+ try {
+ if (title) {
+ const titleData = jsonData.find((item) => item.Title === title);
+ if (!titleData) throw new Error('Title not found');
+
+ const keys = Object.keys(titleData).filter((key) => key !== 'Title');
+ if (keys.length === 0) throw new Error('No items found under specified title');
+
+ const randomKey = keys[Math.floor(Math.random() * keys.length)];
+ result = randomKey;
+ } else {
+ const items = jsonData.flatMap((item) => Object.keys(item).filter((key) => key !== 'Title'));
+ if (items.length === 0) throw new Error('No items found in JSON');
+
+ const randomItem = items[Math.floor(Math.random() * items.length)];
+ result = randomItem;
+ }
+ } catch (error) {
+ console.error(`Error accessing data: ${error}`);
+ this.storeValue(undefined, storage, varName, cache);
+ return this.callNextAction(cache);
+ }
+
+ this.storeValue(result, storage, varName, cache);
+ this.callNextAction(cache);
+ },
+
+ mod() {},
+};
diff --git a/actions/json_read_MOD.js b/actions/json_read_MOD.js
new file mode 100644
index 00000000..dd85f0f0
--- /dev/null
+++ b/actions/json_read_MOD.js
@@ -0,0 +1,102 @@
+const fs = require('fs');
+const path = require('path');
+
+module.exports = {
+ name: 'Read JSON File',
+ section: 'File Stuff',
+ fields: ['filepath', 'title', 'contentTitle', 'storage', 'varName'],
+
+ subtitle(data) {
+ return `Read JSON file "${data.filepath}"`;
+ },
+
+ variableStorage(data, varType) {
+ if (parseInt(data.storage, 10) !== varType) return;
+ return [data.varName, 'Unknown'];
+ },
+
+ html() {
+ return `
+
+
+ File Path
+
+
+
+ Title
+
+
+
+ Content Title
+
+
+
+
+
+
+ `;
+ },
+
+ init() {},
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ let filepath = this.evalMessage(data.filepath, cache);
+ const title = this.evalMessage(data.title, cache);
+ const contentTitle = this.evalMessage(data.contentTitle, cache);
+ const storage = parseInt(data.storage, 10);
+ const varName = this.evalMessage(data.varName, cache);
+
+ if (filepath.startsWith('./')) {
+ filepath = path.join(__dirname, '..', filepath.substring(2));
+ }
+
+ let jsonData;
+
+ try {
+ if (fs.existsSync(filepath)) {
+ const fileData = fs.readFileSync(filepath);
+ if (fileData.length === 0) {
+ console.warn('JSON file is empty.');
+ this.storeValue(undefined, storage, varName, cache);
+ return this.callNextAction(cache);
+ }
+ jsonData = JSON.parse(fileData);
+ } else {
+ throw new Error('File does not exist');
+ }
+ } catch (error) {
+ console.error(`Error reading JSON file: ${error}`);
+ this.storeValue(undefined, storage, varName, cache);
+ return this.callNextAction(cache);
+ }
+
+ let result;
+ try {
+ const titleData = jsonData.find((item) => item.Title === title);
+ if (!titleData) throw new Error('Title not found');
+
+ if (contentTitle.includes('/')) {
+ const contentKeys = contentTitle.split('/');
+ result = {};
+ for (const key of contentKeys) {
+ if (titleData[key] !== undefined) {
+ result[key] = titleData[key];
+ }
+ }
+ } else {
+ if (titleData[contentTitle] === undefined) throw new Error('Content Title not found');
+ result = titleData[contentTitle];
+ }
+ } catch (error) {
+ console.error(`Error accessing data: ${error}`);
+ this.storeValue(undefined, storage, varName, cache);
+ return this.callNextAction(cache);
+ }
+
+ this.storeValue(result, storage, varName, cache);
+ this.callNextAction(cache);
+ },
+
+ mod() {},
+};
diff --git a/actions/json_write_MOD.js b/actions/json_write_MOD.js
new file mode 100644
index 00000000..682462b5
--- /dev/null
+++ b/actions/json_write_MOD.js
@@ -0,0 +1,187 @@
+const fs = require('fs');
+const path = require('path');
+
+module.exports = {
+ name: 'JSON File Control',
+ section: 'File Stuff',
+ fields: ['filepath', 'action', 'title', 'contentTitle', 'contentText', 'newTitle', 'oldTitle', 'deleteContentTitle'],
+ meta: {
+ version: '2.1.7',
+ preciseCheck: false,
+ author: 'DBM Mods',
+ authorUrl: 'https://github.com/dbm-network/mods',
+ },
+
+ subtitle(data) {
+ return `Perform JSON operations on ${data.filepath}`;
+ },
+
+ html() {
+ return `
+
+ `;
+ },
+
+ init() {
+ const { glob, document } = this;
+
+ glob.onChangeAction = function onChangeAction(event) {
+ const value = event.value;
+ document.getElementById('titleSection').style.display =
+ value === 'addTitle' || value === 'addContent' || value === 'renameContent' ? 'block' : 'none';
+ document.getElementById('contentSection').style.display = value === 'addContent' ? 'block' : 'none';
+ document.getElementById('renameSection').style.display =
+ value === 'renameContent' || value === 'renameTitle' ? 'block' : 'none';
+ document.getElementById('deleteSection').style.display = value === 'deleteContent' ? 'block' : 'none';
+ };
+
+ glob.onChangeAction(document.getElementById('action'));
+ },
+
+ async action(cache) {
+ const data = cache.actions[cache.index];
+ let filepath = this.evalMessage(data.filepath, cache);
+
+ if (filepath.startsWith('./')) {
+ filepath = path.join(__dirname, '..', filepath.substring(2));
+ }
+
+ const action = data.action;
+ const title = this.evalMessage(data.title, cache);
+ const contentTitle = this.evalMessage(data.contentTitle, cache);
+ const contentText = this.evalMessage(data.contentText, cache);
+ const oldTitle = this.evalMessage(data.oldTitle, cache);
+ const newTitle = this.evalMessage(data.newTitle, cache);
+ const deleteContentTitle = this.evalMessage(data.deleteContentTitle, cache);
+
+ // Load JSON file
+ let jsonData;
+ try {
+ if (fs.existsSync(filepath)) {
+ const fileData = fs.readFileSync(filepath);
+ jsonData = JSON.parse(fileData);
+ } else {
+ jsonData = [];
+ }
+ } catch (error) {
+ console.error(`Error reading JSON file: ${error}`);
+ jsonData = [];
+ }
+
+ let target;
+
+ switch (action) {
+ case 'addTitle':
+ if (title) {
+ jsonData.push({ Title: title });
+ }
+ break;
+ case 'addContent':
+ target = jsonData.find((item) => item.Title === title);
+ if (!target) {
+ target = { Title: title };
+ jsonData.push(target);
+ }
+ if (contentTitle.includes('/')) {
+ const keys = contentTitle.split('/');
+ keys.reduce(function addNestedContent(obj, key, index) {
+ if (index === keys.length - 1) {
+ obj[key] = isNaN(contentText) ? contentText : parseFloat(contentText);
+ } else {
+ obj[key] = obj[key] || {};
+ }
+ return obj[key];
+ }, target);
+ } else {
+ target[contentTitle] = isNaN(contentText) ? contentText : parseFloat(contentText);
+ }
+ break;
+ case 'renameContent':
+ jsonData.forEach((item) => {
+ if (item.Title === title && item[contentTitle]) {
+ item[newTitle] = item[contentTitle];
+ delete item[contentTitle];
+ }
+ });
+ break;
+ case 'renameTitle':
+ jsonData.forEach((item) => {
+ if (item.Title === oldTitle) {
+ item.Title = newTitle;
+ }
+ });
+ break;
+ case 'deleteContent':
+ jsonData.forEach((item) => {
+ if (item.Title === title) {
+ if (deleteContentTitle.includes('/')) {
+ const keys = deleteContentTitle.split('/');
+ keys.reduce(function deleteNestedContent(obj, key, index) {
+ if (index === keys.length - 1) {
+ delete obj[key];
+ } else {
+ return obj[key];
+ }
+ return obj;
+ }, item);
+ } else {
+ delete item[deleteContentTitle];
+ }
+ }
+ });
+ break;
+ case 'deleteTitle':
+ jsonData = jsonData.filter((item) => item.Title !== title);
+ break;
+ }
+
+ // Save JSON file
+ try {
+ fs.writeFileSync(filepath, JSON.stringify(jsonData, null, 2));
+ } catch (error) {
+ console.error(`Error writing JSON file: ${error}`);
+ }
+
+ this.callNextAction(cache);
+ },
+
+ mod() {},
+};