Roll20 uses cookies to improve your experience on our site. Cookies enable you to enjoy certain features, social sharing functionality, and tailor message and display ads to your interests on our site and others. They also help us understand how our site is being used. By continuing to use our site, you consent to our use of cookies. Update your cookie preferences .
×
Create a free account

[Script] Total for inline rolls.

I wrote a very simple script to print the total of inline rolls made with a + in front of them. (Feel free to berate my coding habbits.) If you want to have unique inline rolls, and total them, you simply write it like this. +[[roll]] Any roll in the chat block you don't want to total just place them inline as normal. [[roll]]. Input: I've added these two numbers +[[20]] +[[100]] but not this number [[5]]. Output: I've added these two numbers +20 +100 but not this number 5. Total: 120 rolladdition = 0; on("chat:message", function(msg) { if(msg.type === "general" && msg.inlinerolls && msg.who !== 'Total'){ var rolls = -1 + msg.inlinerolls.length; if(msg.content.indexOf('$[[0]]') !== -1) { rolladdition = 0; } var arrayMatch = msg.content.match(/\+\$\[\[\d+\]\]/g); if(arrayMatch){ for (var i=0; i < arrayMatch.length; i++){ rolladdition += Number(msg.inlinerolls[arrayMatch[i].match(/\d+/)[0]].results.total); } } if(rolladdition > 0 && msg.content.indexOf('$[['+rolls+']]') !== -1){ sendChat('Total','[['+rolladdition+']]'); rolladdition = 0; } }});
1424892507
The Aaron
Pro
API Scripter
Ripshot said: (Feel free to berate my coding habbits.) Well.. since you're asking... It's really not that bad. =D I'd suggest declaring your rolladdition variable with a var . Moreover, I'd move it into an anonymous function (closure) so as not to pollute the global scope with variables unnecessarily. (BTW, most people don't realize that all API scripts are concatenated together into a single file when the sandbox is spun up, so a variable declared in the global scope will be overwritten by a later variable of the same name.) Probably the easiest way to do this is to just use a function passed to on('ready',...): on('ready',function(){ var rolladdition = 0; on("chat:message", function(msg) { if(msg.type === "general" && msg.inlinerolls && msg.who !== 'Total'){ var rolls = -1 + msg.inlinerolls.length; if(msg.content.indexOf('$[[0]]') !== -1) { rolladdition = 0; } var arrayMatch = msg.content.match(/\+\$\[\[\d+\]\]/g); if(arrayMatch){ for (var i=0; i < arrayMatch.length; i++){ rolladdition += Number(msg.inlinerolls[arrayMatch[i].match(/\d+/)[0]].results.total); } } if(rolladdition > 0 && msg.content.indexOf('$[['+rolls+']]') !== -1){ sendChat('Total','[['+rolladdition+']]'); rolladdition = 0; } }}); });
I knew you were going to say something like this! But that is okay, when I posted that variable outside, I was thinking... Well if someone else declares, I'm screwed. I was calling it total, and thought, naw, that is just ASKING for someone to ram into it, I'll rename to rolladdition. As always thanks, I can take criticism, my goal is to become more effective.
1424896410
The Aaron
Pro
API Scripter
=D
1424899875
Lithl
Pro
Sheet Author
API Scripter
rolladdition += Number(msg.inlinerolls[arrayMatch[i].match(/\d+/)[0]].results.total); There is no need to call the Number function here (and inf fact, without "new Number(...)", you're not correctly using the Number constructor). If you want to ensure that something will be an integer, use parseInt. If you want to ensure that something will be a number but it's not necessarily an integer, use parseFloat.
1424900290
The Aaron
Pro
API Scripter
Nice catch, Brian, I didn't notice that. =D It's usually a good idea to pass a radix to the parse functions: parseInt( SomeString, 10) // parses a decimal number
I added number in there, because I lifted part of this from my attribute modification code. Numbers are stored as strings in attributes, so to do math I had to convert them 1st. I was unaware of the parseInt, and I will make modifications to this and my other code as well. Again, I'm not a coder, so I didn't know the 'proper' way to convert numbers stored as strings into digits. Thanks again!
After reading number() and parseInt() I'm not sure if I would want to use parseInt. Number will return NaN for anything that has any character in it. parseInt just truncates it. Seems they are very similar just slightly different use cases. Of course I could write my own function that does a match on any alpha numeric character, and then returns NaN, and if not, use parseInt to convert it. Not too worried about micro-speed ups... Am I not understanding the differences. It seems they offer different features. (For this particular use, you are correct I don't think I need them, I'll check the log)
1424916079

Edited 1424916150
Number(x) is valid; it's essentially equivalent to "(new Number(x)).valueOf()" (although the former is probably better for performance). Number(x) returns the primitive value (the desired behavior), whereas "new Number(x)" returns the Number wrapper object (which would happen to work because the + operator would coerce it to a primitive value, but is less obvious).
1424930150
Lithl
Pro
Sheet Author
API Scripter
Ripshot said: Am I not understanding the differences. It seems they offer different features. (For this particular use, you are correct I don't think I need them, I'll check the log) Number is intended to be the constructor for Number objects (with the syntax "var foo = new Number(...)"). parseInt and parseFloat are intended to be used to convert arbitrary values into integers (for parseInt) or arbitrary numbers (for parseFloat). If you're curious, it's also possible to use the unary identity operator in place of parseFloat for many potential operations (eg: var foo = +'5.5'), and it is possible to use the bitwise OR operator with 0 in place of parseInt for many potential operations (eg: var foo = '5'|0). parseInt and parseFloat are generally considered superior to the identity operator and the bitwise OR operator, but they are also potential options.
1424942195

Edited 1424942241
I'd generally suggest avoiding using coercion (e.g. via the + operator) just because it's not as clear what's going on (e.g. +'1' and 0+'1' both yield 1, but '0'+'1' and '0'+1 both yield '01'), whereas explicitly calling a function to cast to a numeric type makes it obvious what you intend to do. The differences between Number and parseFloat aren't all that apparent for your use case (if you're always passing in strings which are valid numbers, their respective behavior is identical, and many implementations use the same internals for them). The differences have to do with how they handle invalid strings (Number yields NaN for a nonempty invalid string, and 0 for an empty string; parseFloat yields the number that results from parsing anything valid at the start of an invalid string, and NaN if there is no valid part of the string) and non-string arguments (Number will cast any value to a numeric value; parseFloat will only take a string argument).
1424947474
Lithl
Pro
Sheet Author
API Scripter
manveti said: I'd generally suggest avoiding using coercion (e.g. via the + operator) just because it's not as clear what's going on (e.g. +'1' and 0+'1' both yield 1, but '0'+'1' and '0'+1 both yield '01'), whereas explicitly calling a function to cast to a numeric type makes it obvious what you intend to do. Actually, 0+'1' yields '01'. However, 0+'1' is not utilizing the unary identity operator, is using the binary addition operator. Incorporating the identity operator would be 0+(+'1'), which does yield 1.
1424962331
The Aaron
Pro
API Scripter
It's probably a moot point, as inlinerolls[].results.total will never be anything but a number. However, if it COULD be something other than a number you'd have an error regardless of which you chose to use as NaN + anything is NaN (or literally not a number at the very least... NaN+{}=NaN[object Object] ). When using Number or parseInt() or parseFloat(), you probably want to include a guard default, which you can do using Javascript's peculiarly different || operator: rolladdition += Number(msg.inlinerolls[arrayMatch[i].match(/\d+/)[0]].results.total) || 0 ; Personally, I would use parseInt() because I think it sets the reader's expectation about the data you are expecting to get and it is explicit about the format of that data. It is well ingrained in Brian's and my minds that constructor functions are not to be used without new, but in reality that's a much more important rule when it comes to user created constructor functions as they generally don't provide the additional wiring to make that do something reasonable.
Brian said: manveti said: I'd generally suggest avoiding using coercion (e.g. via the + operator) just because it's not as clear what's going on (e.g. +'1' and 0+'1' both yield 1, but '0'+'1' and '0'+1 both yield '01'), whereas explicitly calling a function to cast to a numeric type makes it obvious what you intend to do. Actually, 0+'1' yields '01'. However, 0+'1' is not utilizing the unary identity operator, is using the binary addition operator. Incorporating the identity operator would be 0+(+'1'), which does yield 1. So it does. I had thought the binary + operator coerced the second operand to the type of the first, but I guess that's some other language. But hey, this way it does a better job of reinforcing my point: if you're depending on rules that are esoteric enough that an experienced programmer is getting them wrong, you should probably consider something more explicit.