Skip to content

Commit ef10e53

Browse files
committed
Meta Toolbox 1-Click Release
1 parent 09edfe2 commit ef10e53

23 files changed

+6407
-1300
lines changed

APILogic/2.03/APILogic.js

+765
Large diffs are not rendered by default.

APILogic/APILogic.js

+182-1,209
Large diffs are not rendered by default.

APILogic/script.json

+10-4
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
{
22
"name": "APILogic",
33
"script": "APILogic.js",
4-
"version": "1.2.1",
5-
"description": "APILogic provides chat input logical constructs for shaping the command line, including IF, ELSEIF, and ELSE. It provides a way to define terms for text-replacment operations, or to name condition sets to re-use later in the logical processing. It also allows for math operations right in a macro's command line, as well as variable muling to track values between rolls.\r\rFor more information, see the original API forum thread:\r\rhttps://app.roll20.net/forum/post/9771314/script-apilogic-gives-if-slash-elseif-slash-else-processing-to-other-scripts/",
4+
"version": "2.0.3",
5+
"description": "APILogic is a meta-script and part of the Meta-Toolbox. APILogic provides chat input logical constructs for shaping the command line, including IF, ELSEIF, and ELSE. It provides a way to define terms for text-replacment operations, or to name condition sets to re-use later in the logical processing. \r\rFor more information, see the original API forum thread:\r\r[APILogic Forum Thread](https://app.roll20.net/forum/post/9771314/script-apilogic-gives-if-slash-elseif-slash-else-processing-to-other-scripts/)\r\rOr read about the full set of meta-scripts available: \r\r[Meta Toolbox Forum Thread](https://app.roll20.net/forum/post/10005695/script-set-the-meta-toolbox)",
66
"authors": "timmaugh",
77
"roll20userid": "5962076",
88
"useroptions": [],
9-
"dependencies": [ "libInline" ],
109
"modifies": {
1110
"state.APILogic": "read, write",
1211
"attribute.characterid": "read",
@@ -19,5 +18,12 @@
1918
"ability.name": "read, write",
2019
"ability.action": "read, write"
2120
},
22-
"conflicts": []
21+
"conflicts": [],
22+
"previousversions": [
23+
"1.0.1",
24+
"1.1.2",
25+
"1.1.3",
26+
"1.2.0",
27+
"1.2.1"
28+
]
2329
}

Fetch/Fetch.js

+705
Large diffs are not rendered by default.

Fetch/script.json

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
"name": "Fetch",
3+
"script": "Fetch.js",
4+
"version": "1.0.4",
5+
"previousversions": [ "1.0.0", "1.0.1" ],
6+
"description": "Fetch is a meta-script and part of the Meta-Toolbox. Fetch offers a unified syntax to expand the amount of things that can be retrieved with simple token or sheet calls. You can retrieve any token property, character property, sheet attribute, repeating attribute, ability, or macro with syntax that is intentionally very similar to Roll20's own syntax structures.\r\rToken property : @(selected.currentside)\rSheet Attribute: @(selected.Strength)\rSheet Attribute: @(Bob the Hirsute.Strength.max)\rRepeating Attr : *(Englebert Slaptiback.spells.[spell_name~Fireball prepared].spell_roll)\r\rIt also expands the source of the returned sheet item to include 'speaker'.\r\r@(speaker.Strength.max) ... and can return the rowID of a repeating attribute, the row number ($0), or the name of either brand of reference.\r\rNot only do these offer the advantage of not breaking the chat message if they don't exist (the way a standard token or sheet item call would), they also give you the ability to substitute in a default value should the one you are looking for not exist: \r\r@(The President of Burundi.Coffee[default value here]) \r\rFor more information, see the original API forum thread:\r\rhttps://app.roll20.net/forum/post/10005732/meta-script-fetch-retrieve-attributes-repeating-attributes-abilities-or-token-properties)\r\rOr read about the full set of meta-scripts available: \r\r[Meta Toolbox Forum Thread](https://app.roll20.net/forum/post/10005695/script-set-the-meta-toolbox)",
7+
"authors": "timmaugh",
8+
"roll20userid": "5962076",
9+
"useroptions": [],
10+
"modifies": {
11+
"state.Fetch": "read, write",
12+
"attribute.characterid": "read",
13+
"attribute.current": "read",
14+
"attribute.id": "read",
15+
"attribute.max": "read",
16+
"attribute.name": "read",
17+
"attribute.type": "read"
18+
},
19+
"conflicts": []
20+
}

MathOps/1.0.2/MathOps.js

+316
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,316 @@
1+
/*
2+
=========================================================
3+
Name : MathOps
4+
GitHub : https://github.com/TimRohr22/Cauldron/tree/master/MathOps
5+
Roll20 Contact : timmaugh
6+
Version : 1.0.2
7+
Last Update : 5/6/2021
8+
=========================================================
9+
*/
10+
var API_Meta = API_Meta || {};
11+
API_Meta.MathOps = { offset: Number.MAX_SAFE_INTEGER, lineCount: -1 };
12+
{
13+
try { throw new Error(''); } catch (e) { API_Meta.MathOps.offset = (parseInt(e.stack.split(/\n/)[1].replace(/^.*:(\d+):.*$/, '$1'), 10) - (13)); }
14+
}
15+
16+
const MathOps = (() => {
17+
const apiproject = 'MathOps';
18+
const version = '1.0.2';
19+
const schemaVersion = 0.1;
20+
API_Meta[apiproject].version = version;
21+
const vd = new Date(1620275212489);
22+
const versionInfo = () => {
23+
log(`\u0166\u0166 ${apiproject} v${API_Meta[apiproject].version}, ${vd.getFullYear()}/${vd.getMonth() + 1}/${vd.getDate()} \u0166\u0166 -- offset ${API_Meta[apiproject].offset}`);
24+
if (!state.hasOwnProperty(apiproject) || state[apiproject].version !== schemaVersion) {
25+
log(` > Updating ${apiproject} Schema to v${schemaVersion} <`);
26+
switch (state[apiproject] && state[apiproject].version) {
27+
28+
case 0.1:
29+
/* break; // intentional dropthrough */ /* falls through */
30+
31+
case 'UpdateSchemaVersion':
32+
state[apiproject].version = schemaVersion;
33+
break;
34+
35+
default:
36+
state[apiproject] = {
37+
version: schemaVersion,
38+
};
39+
break;
40+
}
41+
}
42+
};
43+
const logsig = () => {
44+
// initialize shared namespace for all signed projects, if needed
45+
state.torii = state.torii || {};
46+
// initialize siglogged check, if needed
47+
state.torii.siglogged = state.torii.siglogged || false;
48+
state.torii.sigtime = state.torii.sigtime || Date.now() - 3001;
49+
if (!state.torii.siglogged || Date.now() - state.torii.sigtime > 3000) {
50+
const logsig = '\n' +
51+
' _____________________________________________ ' + '\n' +
52+
' )_________________________________________( ' + '\n' +
53+
' )_____________________________________( ' + '\n' +
54+
' ___| |_______________| |___ ' + '\n' +
55+
' |___ _______________ ___| ' + '\n' +
56+
' | | | | ' + '\n' +
57+
' | | | | ' + '\n' +
58+
' | | | | ' + '\n' +
59+
' | | | | ' + '\n' +
60+
' | | | | ' + '\n' +
61+
'______________|_|_______________|_|_______________' + '\n' +
62+
' ' + '\n';
63+
log(`${logsig}`);
64+
state.torii.siglogged = true;
65+
state.torii.sigtime = Date.now();
66+
}
67+
return;
68+
};
69+
70+
const mathprocessor = (() => {
71+
const tokenize = code => {
72+
let results = [];
73+
let tokenRegExp = /\s*([A-Za-z\s'"`]+|-?[0-9]+(\.[0-9]+)?|\S)\s*/g;
74+
75+
let m;
76+
while ((m = tokenRegExp.exec(code)) !== null)
77+
results.push(m[1]);
78+
return results;
79+
};
80+
81+
const isNumber = token => {
82+
return token !== undefined && token.match(/^-?[0-9]*.?[0-9]+$/) !== null;
83+
};
84+
85+
const isName = token => {
86+
return token !== undefined && token.match(/^[A-Za-z\s'"`]+$/) !== null;
87+
};
88+
89+
const parse = o => {
90+
let tokens = tokenize(o.code);
91+
let position = 0;
92+
const peek = () => {
93+
return tokens[position];
94+
};
95+
const peek1 = () => {
96+
if (position < tokens.length - 1) {
97+
return tokens[position + 1];
98+
}
99+
};
100+
101+
const consume = token => {
102+
position++;
103+
};
104+
105+
const parsePrimaryExpr = () => {
106+
let t = peek();
107+
108+
if (isNumber(t)) {
109+
consume(t);
110+
return { type: "number", value: t };
111+
} else if (isName(t)) {
112+
if (funcbank.hasOwnProperty(t.toLowerCase()) && peek1() === '(') {
113+
let f = t.toLowerCase();
114+
let p = [];
115+
consume(t);
116+
consume('(');
117+
while (peek() !== ')') {
118+
if (peek() === ',') {
119+
consume(',');
120+
} else {
121+
p.push(parseExpr());
122+
}
123+
}
124+
if (peek() !== ")") throw "Expected )";
125+
consume(')');
126+
return { type: 'func', func: f, params: p };
127+
} else {
128+
consume(t);
129+
return { type: "name", id: t };
130+
}
131+
} else if (t === "(") {
132+
consume(t);
133+
let expr = parseExpr();
134+
if (peek() !== ")") throw "Expected )";
135+
consume(")");
136+
return expr;
137+
} else {
138+
throw "Expected a number, a variable, or parentheses";
139+
}
140+
};
141+
142+
const parseMulExpr = () => {
143+
let expr = parsePrimaryExpr();
144+
let t = peek();
145+
while (t === "*" || t === "/" || t === "%") {
146+
consume(t);
147+
let rhs = parsePrimaryExpr();
148+
expr = { type: t, left: expr, right: rhs };
149+
t = peek();
150+
}
151+
return expr;
152+
};
153+
const parseExpr = () => {
154+
let expr = parseMulExpr();
155+
let t = peek();
156+
while (t === "+" || t === "-") {
157+
consume(t);
158+
let rhs = parseMulExpr();
159+
expr = { type: t, left: expr, right: rhs };
160+
t = peek();
161+
}
162+
return expr;
163+
};
164+
let result = parseExpr();
165+
if (position !== tokens.length) throw "Unexpected '" + peek() + "'";
166+
return result;
167+
};
168+
const funcbank = {
169+
abs: Math.abs,
170+
min: Math.min,
171+
max: Math.max,
172+
acos: Math.acos,
173+
acosh: Math.acosh,
174+
asin: Math.asin,
175+
asinh: Math.asinh,
176+
atan: Math.atan,
177+
atanh: Math.atanh,
178+
atantwo: Math.atan2,
179+
cbrt: Math.cbrt,
180+
ceiling: Math.ceil,
181+
cos: Math.cos,
182+
cosh: Math.cosh,
183+
exp: Math.exp,
184+
expmone: Math.expm1,
185+
floor: Math.floor,
186+
hypot: Math.hypot,
187+
log: Math.log,
188+
logonep: Math.log1p,
189+
logten: Math.log10,
190+
logtwo: Math.log2,
191+
pow: (v, e = 1) => Math.pow(v, e),
192+
rand: Math.random,
193+
randb: (v1, v2) => { return Math.random() * (Math.max(v1, v2) - Math.min(v1, v2) + 1) + Math.min(v1, v2) },
194+
randib: (v1, v2) => {
195+
let min = Math.ceil(Math.min(v1, v2));
196+
let max = Math.floor(Math.max(v1, v2));
197+
return Math.floor(Math.random() * (max - min) + min);
198+
},
199+
randa: (...v) => v[Math.floor(Math.random() * v.length)],
200+
round: (v, d = 0) => Math.round(v * 10 ** d) / 10 ** d,
201+
sin: Math.sin,
202+
sinh: Math.sinh,
203+
sqrt: Math.sqrt,
204+
tan: Math.tan,
205+
tanh: Math.tanh,
206+
trunc: Math.trunc
207+
};
208+
const knownbank = {
209+
e: Math.E,
210+
pi: Math.PI,
211+
lntwo: Math.LN2,
212+
lnten: Math.LN10,
213+
logtwoe: Math.LOG2E,
214+
logtene: Math.LOG10E
215+
}
216+
const isNum = (v) => +v === +v;
217+
const typeprocessor = {
218+
'-': (a, b) => { return isNum(a) && isNum(b) ? Number(a) - Number(b) : `${a}-${b}`; },
219+
'+': (a, b) => { return isNum(a) && isNum(b) ? Number(a) + Number(b) : `${a}+${b}`; },
220+
'/': (a, b) => { return isNum(a) && isNum(b) ? Number(a) / Number(b) : `${a}/${b}`; },
221+
'*': (a, b) => { return isNum(a) && isNum(b) ? Number(a) * Number(b) : `${a}*${b}`; },
222+
'%': (a, b) => { return isNum(a) && isNum(b) ? Number(a) % Number(b) : `${a}%${b}`; }
223+
};
224+
const isString = (s) => 'string' === typeof s || s instanceof String;
225+
const evalops = o => {
226+
if (!o.code || !isString(o.code)) return;
227+
o.known = o.known || {};
228+
Object.assign(o.known, knownbank);
229+
try {
230+
const getVal = t => {
231+
switch (t.type) {
232+
case 'number':
233+
return t.value;
234+
case 'name':
235+
return o.known[t.id.trim()] || t.id;
236+
case 'func':
237+
return funcbank[t.func](...t.params.map(p => getVal(p)));
238+
default:
239+
return typeprocessor[t.type](getVal(t.left), getVal(t.right));
240+
}
241+
};
242+
return getVal(parse(o));
243+
} catch (error) {
244+
return { message: error };
245+
}
246+
};
247+
return evalops;
248+
})();
249+
const mathrx = /(\()?{&\s*math\s*([^}]+)\s*}((?<=\({&\s*math\s*([^}]+)\s*})\)|\1)/g;
250+
251+
const testConstructs = c => {
252+
let result = mathrx.test(c);
253+
mathrx.lastIndex = 0;
254+
return result;
255+
};
256+
const handleInput = (msg, msgstate) => {
257+
let funcret = { runloop: false, status: 'unchanged', notes: '' };
258+
if (msg.type !== 'api' || !testConstructs(msg.content)) return funcret;
259+
if (!msgstate && scriptisplugin) return funcret;
260+
let status = [];
261+
let notes = [];
262+
msg.content = msg.content.replace(mathrx, (m, padding, g1) => {
263+
g1 = g1.replace(/\$\[\[(\d+)]]/g, (m1, roll) => {
264+
let rollval;
265+
if (msg.parsedinline) {
266+
rollval = msg.parsedinline[roll].value;
267+
} else if (msg.inlinerolls && msg.inlinerolls[roll]) {
268+
rollval = msg.inlinerolls[roll].results.total;
269+
} else {
270+
rollval = 0;
271+
}
272+
return rollval;
273+
});
274+
let result = mathprocessor({ code: g1, known: msg.variables || {} });
275+
if (result.message) { // error
276+
status.push('unresolved');
277+
notes.push(result.message);
278+
return m;
279+
} else {
280+
status.push('changed');
281+
return result;
282+
}
283+
});
284+
funcret.runloop = (status.includes('changed') || status.includes('unresolved'));
285+
funcret.status = status.reduce((m, v) => {
286+
switch (m) {
287+
case 'unchanged':
288+
m = v;
289+
break;
290+
case 'changed':
291+
m = v === 'unresolved' ? v : m;
292+
break;
293+
case 'unresolved':
294+
break;
295+
}
296+
return m;
297+
});
298+
funcret.notes = notes.join('<br>');
299+
return funcret;
300+
};
301+
302+
let scriptisplugin = false;
303+
const mathops = (m, s) => handleInput(m, s);
304+
on('chat:message', handleInput);
305+
on('ready', () => {
306+
versionInfo();
307+
logsig();
308+
scriptisplugin = (typeof ZeroFrame !== `undefined`);
309+
if (typeof ZeroFrame !== 'undefined') {
310+
ZeroFrame.RegisterMetaOp(mathops, { priority: 55, handles: ['math'] });
311+
}
312+
});
313+
return {
314+
};
315+
})();
316+
{ try { throw new Error(''); } catch (e) { API_Meta.MathOps.lineCount = (parseInt(e.stack.split(/\n/)[1].replace(/^.*:(\d+):.*$/, '$1'), 10) - API_Meta.MathOps.offset); } }

0 commit comments

Comments
 (0)