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 .
×

[BUG] API: sendChat(who, msg, function(ops) {...}) overload does not handle multiline messages correctly.

Problem Description: The API sendChat function has two overloads, one of which accepts a function callback as an argument. This argument is called to process the chat message rather than sending it to the chat window. The callback contains a single argument which is an ARRAY of chat messages to be processed by the function. When sending a chat message with multiple lines to the callback, the array contains one element per line, but each element of the array in the call back contains information only for the final line/message passed in the msg argument of the sendChat function call. The intended behavior of this function, presumably, is for each element in the ops array to contain information for each line in the msg argument. Steps to Reproduce: Here is a function which will duplicate the error: function SendChatBug() { text = "FOO\nFOO\nBAR"; //text to use as msg //call sendChat with function callback sendChat("api", text, function(ops) { log(ops.length); //check the length of the ops array; expected value = 3 log(ops); //dump the contents of ops; incorrect behavior displayed here }); } Here is the JSON result of the above log(ops); line, with additional lines added for readability [{"who":"api","type":"general","content":"BAR","playerid":"API","avatar":false,"inlinerolls":{}},{"who":"api","type":"general","content":"BAR","playerid":"API","avatar":false,"inlinerolls":{}},{"who":"api","type":"general","content":"BAR","playerid":"API","avatar":false,"inlinerolls":{}}] You can see that the content of each of the message results in the ops argument is "BAR" even though two of the lines in MSG had a value of FOO. This is unexpected behavior. Environment Details: OS: Windows 7 Browser: Chrome 35.0.1916.153 Feel free to contact me for more information.
Has anyone be able to reproduce this?
1405461100
Lithl
Pro
Sheet Author
API Scripter
While certainly a bug, I doubt it's a common use-case (particularly since the wiki example shows only a single line). What's your use-case for this, perhaps there is a workaround for you until it gets fixed?
I have a special game rule I want to implement whereby I make two attack rolls simultaneously, against separate target defense values. If either of the rolls hits, then damage will be applied automatically, but should not be applied twice if both attack rolls hit.
1405706019
The Aaron
Roll20 Production Team
API Scripter
Why are you specifically interested in sending this with \n in it? Could you not just send it with some other separator or as 3 separate messages? If you are supplying a callback function, the text is not displayed anywhere to begin with, and I assume you are just parsing the results. (or planning to parse them)
The behavior is dependent on two separate rolls. According to the documentation, the results array should contain one element per message - hence the /n: two separate rolls equates to two separate roll results. My intent is to parse the rolls after the fact, but I need to look at both sets of results in the same function to determine whether or not a hit has been scored. To my knowledge, I can't do this with two separate sendChat executions and two separate callback functions; the callbacks would not have the results from the other roll, if that makes sense.
1405796854

Edited 1405796911
The Aaron
Roll20 Production Team
API Scripter
You just need to chain your calls together: sendChat ('',' [[1d20]] ', function ( ops ) { sendChat ('',' [[1d20]] ', function ( ops2 ) { sendChat ('','First Result: ' + ops [0].inlinerolls[1].results.total +' Second: ' + ops2 [0].inlinerolls[1].results.total); }); }); First Result: 9 Second: 1 In Javascript, when you create a function within another function, the child function has access to the variables defined in the parent one. This is called a closure . So the second send chat callback has access to the parameter passed to the first callback, ops . It can then use ops and ops2 to do whatever it likes. You could also supply multiple rolls with the inline roll syntax and then just parse the respective inlinerolls[] entries: sendChat ('',' [[1d20]] [[1d20]] ', function ( ops ){ sendChat ('','First Result: ' + ops [0].inlinerolls[1].results.total +' Second: ' + ops [0].inlinerolls[2].results.total); }); First Result: 4 Second: 5 Closures are very powerful, but they take a bit of thinking to wrap your mind around them, particularly if you're used to procedural languages without them. I highly recommend Javascript: The Good Parts [1] by Douglas Crockford. It's a fast read and does a great job of explaining the powerful parts of Javascript, and how to avoid pitfalls. [1] <a href="http://www.amazon.com/JavaScript-Good-Parts-Douglas-Crockford/dp/0596517742" rel="nofollow">http://www.amazon.com/JavaScript-Good-Parts-Douglas-Crockford/dp/0596517742</a>
1405798192
The Aaron
Roll20 Production Team
API Scripter
Just for fun, I did a bit of testing on the original posted problem. Definitely a bug. Here are my results for two tests: For this string: text = "One\nTwo"; You get the second line repeated twice: [ . { . . "who": "api", . . "type": "general", . . "content": "Two", . . "playerid": "API", . . "avatar": false, . . "inlinerolls": {} . }, . { . . "who": "api", . . "type": "general", . . "content": "Two", . . "playerid": "API", . . "avatar": false, . . "inlinerolls": {} . } ] For this string: text = "[[1d6]]\n[[1d8]]" You get two complete copies with the same inline rolls of both dice. [ . { . . "who": "api", . . "type": "general", . . "content": "$$[[1]]", . . "playerid": "API", . . "avatar": false, . . "inlinerolls": { . . . "1": { . . . . "expression": "1d6", . . . . "results": { . . . . . "type": "V", . . . . . "rolls": [ . . . . . . { . . . . . . . "type": "R", . . . . . . . "dice": 1, . . . . . . . "sides": 6, . . . . . . . "mods": {}, . . . . . . . "results": [ . . . . . . . . { . . . . . . . . . "v": 4 . . . . . . . . } . . . . . . . ] . . . . . . } . . . . . ], . . . . . "resultType": "sum", . . . . . "total": 4 . . . . } . . . }, . . . "2": { . . . . "expression": "1d8", . . . . "results": { . . . . . "type": "V", . . . . . "rolls": [ . . . . . . { . . . . . . . "type": "R", . . . . . . . "dice": 1, . . . . . . . "sides": 8, . . . . . . . "mods": {}, . . . . . . . "results": [ . . . . . . . . { . . . . . . . . . "v": 2 . . . . . . . . } . . . . . . . ] . . . . . . } . . . . . ], . . . . . "resultType": "sum", . . . . . "total": 2 . . . . } . . . } . . } . }, . { . . "who": "api", . . "type": "general", . . "content": "$$[[2]]", . . "playerid": "API", . . "avatar": false, . . "inlinerolls": { . . . "1": { . . . . "expression": "1d6", . . . . "results": { . . . . . "type": "V", . . . . . "rolls": [ . . . . . . { . . . . . . . "type": "R", . . . . . . . "dice": 1, . . . . . . . "sides": 6, . . . . . . . "mods": {}, . . . . . . . "results": [ . . . . . . . . { . . . . . . . . . "v": 4 . . . . . . . . } . . . . . . . ] . . . . . . } . . . . . ], . . . . . "resultType": "sum", . . . . . "total": 4 . . . . } . . . }, . . . "2": { . . . . "expression": "1d8", . . . . "results": { . . . . . "type": "V", . . . . . "rolls": [ . . . . . . { . . . . . . . "type": "R", . . . . . . . "dice": 1, . . . . . . . "sides": 8, . . . . . . . "mods": {}, . . . . . . . "results": [ . . . . . . . . { . . . . . . . . . "v": 2 . . . . . . . . } . . . . . . . ] . . . . . . } . . . . . ], . . . . . "resultType": "sum", . . . . . "total": 2 . . . . } . . . } . . } . } ]
Sorry for the delay here. Aaron, that first solution looks good. I had considered it, but was hoping to avoid the inelegance of nesting a callback function inside another. Ah well, I suppose I will have to bite the bullet as my group is already starting an angry peasant riot with torches pitchforks. Thanks for the detailed explanation and diligence in looking into this. I know it's not likely something that is seeing a lot of use at the moment, but it would be nice to see the devs look at it. I think there is potential for multiline and multi-roll processing using the callback overload.
1406568603
The Aaron
Roll20 Production Team
API Scripter
If you use the inline rolls, you only need the sendChat() call with a callback function to process (slightly confusing as my example call back sends the results to the chat window.). Here's a revised example: sendChat ('','[[1d20]] [[1d20]]', function (ops){ log ('','First Result: '+ops[0].inlinerolls[1].results.total +' Second: '+ops[0].inlinerolls[2].results.total); });