Kaspar K. said: Now, instead of chat output, the penalty should be included in the inline roll... Perhaps the script output could be saved in a Mule atribute and then immediately retrieved? Can this be done within the same macro? Yes, generally things can be written and retrieved from a Mule within the same macro... however in this case the output of the range script was different than the value you wanted to store, so it would have taken changing the output text of the range script to include the Muler verbiage. Instead, I took the above script and rejiggered it to be a Plugger plugin. It should still run from the command line if you wanted to send it through on its own: !range @{target|token_id} @{selected|token_id} !range @{target|Target 1|token_id} @{target|Target 2|token_id} !range @{target|Get Distance From Selected to this Token|token_id} But now you can also return the value of the range modifier to the command line by embedding it in a Plugger EVAL structure: {& eval}range(@{target|token_id}){& /eval} To have that work in an inline roll, you have to delay the roll until the range modifier is returned. That would look like this... [\][\] ... \]\] So plug your roll math into the middle. For a roll of "1d20 minus the range mod" that would be: [\][\]1d20 - {& eval}range(@{target|token_id}){& /eval}\]\] Deferring a roll like this requires ZeroFrame. Keeping a selected token through all of this might require SelectManager. And obviously, this will require Plugger to run the range script as a plug-in. Here is the re-written script: 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122 // Range script rewrite
// script will work as standalone or as Plugger plugin (to return the range mod to the command line)
const Range = (() => {
// !getRange @{target|1st Target|token_id} @{target|2nd Target|token_id}
const handleInput = msg => {
log(msg.content);
if (msg.type !== "api" || ! /^!range\s+.+/i .test(msg.content)) return ;
let tokens = msg.content.split( /\s+/ , 3 ).slice( 1 );
let id1 = tokens[ 0 ];
let id2 = tokens[ 1 ] || ((msg.selected || [])[ 0 ] || {})._id || undefined ;
log( ` ID1: ${id1} ` );
log( ` ID2: ${id2} ` );
if (!(id1 && id2)) return ;
let token1 = getObj( "graphic" , id1);
let token2 = getObj( "graphic" , id2);
let distance = 0 ;
let rMod;
if (token1 && token2 && token1.get( 'pageid' ) === token2.get( 'pageid' )) {
distance = tokenDistance(token1, token2);
rMod = rangeMod(distance);
if (msg. eval ) {
return rMod;
} else {
sendChat( "" , "/desc Range modifier is " + rMod);
}
} else {
distance = undefined ;
if (token1 && token2 && token1.get( 'pageid' ) !== token2.get( 'pageid' )) {
sendChat( "Range Finder" , "/w " + msg.who + " Tokens are not on the same page!" );
}
if (!token1)
sendChat( "Range Finder" , "/w " + msg.who + " Could not locate first token!" );
if (!token2)
sendChat( "Range Finder" , "/w " + msg.who + " Could not locate second token!" );
}
};
const tokenDistance = (token1, token2) => {
if (token1.get( 'pageid' ) !== token2.get( 'pageid' )) {
log( 'Cannot measure distance between tokens on different pages' );
return ;
}
let distance;
let page = getObj( 'page' , token1.get( 'pageid' ));
let gridType = page.get( 'grid_type' );
switch (gridType) {
case 'hex' :
distance = hexVDistance([token1.get( "left" ), token1.get( "top" )], [token2.get( "left" ), token2.get( "top" )]);
break ;
case 'hexr' :
distance = hexHDistance([token1.get( "left" ), token1.get( "top" )], [token2.get( "left" ), token2.get( "top" )]);
break ;
}
return distance;
};
const hexHDistance = (unit1, unit2) => {
let q1, q2, r1, r2;
q1 = Math .round((unit1[ 0 ] - 46.48512749037782 ) / 69.58512749037783 );
r1 = Math .round((unit1[ 1 ] - 39.8443949917523 ) / 39.8443949917523 );
r1 = Math .floor(r1 / 2 );
q2 = Math .round((unit2[ 0 ] - 46.48512749037782 ) / 69.58512749037783 );
r2 = Math .round((unit2[ 1 ] - 39.8443949917523 ) / 39.8443949917523 );
r2 = Math .floor(r2 / 2 );
return cubeDistance(oddQToCube(q1, r1), oddQToCube(q2, r2));
};
const hexVDistance = (unit1, unit2) => {
let q1, q2, r1, r2;
q1 = Math .round((unit1[ 0 ] - 37.59928099223013 ) / 37.59928099223013 );
r1 = Math .round((unit1[ 1 ] - 43.86582782426834 ) / 66.96582782426833 );
q1 = Math .floor(q1 / 2 );
q2 = Math .round((unit2[ 0 ] - 37.59928099223013 ) / 37.59928099223013 );
r2 = Math .round((unit2[ 1 ] - 43.86582782426834 ) / 66.96582782426833 );
q2 = Math .floor(q2 / 2 );
return cubeDistance(oddRToCube(q1, r1), oddRToCube(q2, r2));
};
const oddRToCube = (q, r) => {
let x, y, z;
x = q - (r - (r & 1 )) / 2 ;
z = r;
y = -x - z;
return [x, y, z];
};
const oddQToCube = (q, r) => {
let x, y, z;
x = q;
z = r - (q - (q & 1 )) / 2 ;
y = -x - z;
return [x, y, z];
};
const cubeDistance = (cube1, cube2) => {
return Math .max( Math .abs(cube1[ 0 ] - cube2[ 0 ]), Math .abs(cube1[ 1 ] - cube2[ 1 ]), Math .abs(cube1[ 2 ] - cube2[ 2 ]));
};
const rangeMod = (distR) => {
switch ( true ) {
case (distR < 3 ):
return 0 ;
case (distR < 4 ):
return - 1 ;
case (distR < 6 ):
return - 2 ;
case (distR < 8 ):
return - 3 ;
case (distR < 11 ):
return - 4 ;
case (distR < 111 ):
return - 5 ;
default :
log( 'not a coded range' );
}
};
const registerEventHandlers = () => {
on( "chat:message" , handleInput);
};
const range = (m) => handleInput(m);
on( "ready" , () => {
registerEventHandlers();
try {
Plugger.RegisterRule(range);
} catch (error) {
log(error);
}
});
})(); EDIT: Corrected 7/20/2021 for error mentioned below.