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

[Help] Pulling info from one API into another

Alright, so here's the down and dirty of it. I find myself time and time again using this at the top of every API script I write. var Master = Master || {}; on("chat:message", function (msg) { if (msg.type != "api"){return}; log(msg.content); //If msg has inline rolls, convert them to integers. if(_.has(msg,'inlinerolls')){ msg.content = _.chain(msg.inlinerolls) .reduce(function(m,v,k){ m['$[['+k+']]']=v.results.total || 0; return m; },{}) .reduce(function(m,v,k){ return m.replace(k,v); },msg.content) .value(); }; //Convert msg.content into callable tags via Master.[Tag] (Ex. Master.target_id) var command = msg.content.split(" ", 1); var n = msg.content.split(" --"); var a = 1; var chatObj = {}; var Tags = ""; var Content = ""; while(n[a]) { Tag = n[a].substring(0,n[a].indexOf("|")); Content = n[a].substring(n[a].indexOf("|") + 1); chatObj[Tag] = Content; a++; }; //log(chatObj); }); Is there any way to make this into a function or to just flat out pull info from it from another API? You know, via var thisApiMaster = MasterAPI.Master; Or something along those lines? I'm a pretty big rookie at this stuff, knowing pretty much just how to bash out an API that makes something I want to happen, happen. Stuff like player-targeted heal spells that won't go over max HP of the target and other simple things. While I have your attention, a question along the same lines. Is there a way to pull a value out of the Powercard script and strong-arm it into one of my scripts? That way we get the nice pretty look of Powercard (which is so nice) but I could still do things like my healing script using those same values? Right now we get around it by rolling the Powercard heal for looks, then a separate macro to literally just inject HP into the selected token. And as we all know, cutting down on the 800 macros most people already have would be a pleasure. Either way, thanks in andvance! EDIT: changed local variable "Master" to "chatObj"
1425458210

Edited 1425458320
Lithl
Pro
Sheet Author
API Scripter
All scripts in a campaign run in the same context. If you have a globally-visible variable "foo" or a globally-visible function "bar" in one script, all scripts in the campaign will have access to foo and bar. This is the main reason why script authors are strongly encouraged to "namespace" their scripts. Instead of creating a bunch of variables and functions that any script can see, you create one object, and put your variables and functions within that object. That way, you only introduce one name into the global scope, and your chances of causing collisions with someone else's script are minimized. For example, if I write a function called "handleInput" and you write a function called "handleInput", and then someone else installs both of our scripts, one of the scripts is going to break because only one version of handleInput will run. However, if I have an object "brian" which contains my version of handleInput, and you have an object "kerberos" which contains your version of handleInput, our respective scripts will be looking for brian.handleInput and kerberos.handleInput, and there won't be any name collisions for someone installing both of our scripts. PS, comment on your posted code: You have a global variable "Master" and a local variable "Master". While the JavaScript engine handles this perfectly fine, with well-defined rules, it makes the script harder for a reader to understand, and might not be doing what you actually want.
The bit at the top was something someone a while ago told me to put at the top of my API to keep them from breaking, keeping it relevant to the title of the API of course. var apiName = apiName || {}; I have no idea what it's for or what it does but nothing's broken yet. I assume this is what you're referring to when you say "namespace"? And I see what you're talking about with the global/local Master thing...that is a problem I had not thought about. I'll just change the local variable to chatObj, because am I right in assuming his code essentially just creates an object out of what was posted to chat? Again, noob. But, moving along with the rest, I can be a little slow. Lets say I create a master API, lets call it "MasterAPI" (Shocker, right? So creative). I want it to take every line of API applicable text that comes through the chat and check it, convert it and log it. So I punch this in chat, !heal --type|Spell --spell|[[3d8+13]] --target|@{target|token_id} MasterAPI catches it and converts it then spits it out in the log menu of the api page. With the line of code log(chatObj); {"type":"Wand","spell":"18","target":"-JjTlUxVK3B8XABPaoXb"} Now I want my heal API to look at this and do it's thing. (I'm not going to post it here, it is the most horrible quick hackjob I have ever done and I intend on doing a full overhaul of the whole system.) But, long story short, it looks at MasterAPI and processes it as such. var target = findObjs ({ _type:"graphic", _id:MasterAPI.chatObj.target //I am assuming pulling a global variable is something like this??? }); var HPcur = parseInt(target.get("bar1_value")); var HPmax = parseInt(target.get("bar1_max")); var HPspell = parseInt(MasterAPI.chatObj.spell); //Again, just an assumption var HPcur = HPcur + HPspell; if (HPcur > HPmax) { var HPcur = HPmax; }; target.set("bar1_value", HPcur + ""); //Please forgive the inherent terribleness of this code. I just punched it up in the chat and can't exactly //Bug test it, but I think it gets the point across. Am I correct in assuming that is how you would pull a global variable? It would probably be better just to pull chatObj and give it a local variable reference but this works for the sake of example. If not, could you give me an example by way of something like, var localVariable = globalVariable; Again, thanks in advance for any help you can give.
1425472287
Lithl
Pro
Sheet Author
API Scripter
Kerberos said: The bit at the top was something someone a while ago told me to put at the top of my API to keep them from breaking, keeping it relevant to the title of the API of course. var apiName = apiName || {}; I have no idea what it's for or what it does but nothing's broken yet. I assume this is what you're referring to when you say "namespace"? Yes, indeed. What that line does is create a variable named "apiName". If a variable with that name already exists and has a truthy value , set it equal to the value it already has. Otherwise, set it equal to the empty object literal. "Truthy" is anything that evaluates to "true" in a boolean statement. Everything is truthy except for the falsey values: null , undefined , 0 , the empty string, NaN , and false . The reason we set the namespace variable equal to itself if it exists is in the case of multiple scripts using the same namespace. If we didn't (in other words, using var apiName = {}; instead), loading a second script with the same namespace would wipe out all variables and functions that were already in the namespace. The reason it's not breaking anything in your script right now is because it's not actually doing anything at all, other than creating an empty object. And that's fine, so long as you don't have anything in the global scope. You need (read: "should use") a namespace when you're going to use a variable or function that would otherwise be in global scope, so that you minimize your footprint on the global scope. Kerberos said: Lets say I create a master API, lets call it "MasterAPI" (Shocker, right? So creative). I want it to take every line of API applicable text that comes through the chat and check it, convert it and log it. So I punch this in chat, !heal --type|Spell --spell|[[3d8+13]] --target|@{target|token_id} MasterAPI catches it and converts it then spits it out in the log menu of the api page. With the line of code log(chatObj); {"type":"Wand","spell":"18","target":"-JjTlUxVK3B8XABPaoXb"} Now I want my heal API to look at this and do it's thing. (I'm not going to post it here, it is the most horrible quick hackjob I have ever done and I intend on doing a full overhaul of the whole system.) But, long story short, it looks at MasterAPI and processes it as such. var target = findObjs ({ _type:"graphic", _id:MasterAPI.chatObj.target //I am assuming pulling a global variable is something like this??? }); var HPcur = parseInt(target.get("bar1_value")); var HPmax = parseInt(target.get("bar1_max")); var HPspell = parseInt(MasterAPI.chatObj.spell); //Again, just an assumption var HPcur = HPcur + HPspell; if (HPcur > HPmax) { var HPcur = HPmax; }; target.set("bar1_value", HPcur + ""); //Please forgive the inherent terribleness of this code. I just punched it up in the chat and can't exactly //Bug test it, but I think it gets the point across. Yes, you've got the gist of it. You could certainly create a script like this: var MasterAPI = MasterAPI || {}; on('chat:message', function(msg) { // ... stuff ... MasterAPI.chatObj[key] = value; // ... stuff ... }); Then, in another script: if (!MasterAPI) { // MasterAPI isn't installed, abort return; } if (!MasterAPI.chatObj) { // MasterAPI isn't working or something like that, abort return; } if (MasterAPI.chatObj.spell) { // ... stuff with the "spell" tag ... } I include those "undefined guards" to help avoid crashing your script. =) I also feel that it's important to point out that this setup you're proposing has potential to blow up in your face if the scripts decide to run in the wrong order, or if many chat messages are coming in at the same time. Instead, I would recommend something like this: var MasterAPI = MasterAPI || {}; MasterAPI.processChatMessage = function(msg) { var chatObj = {}; // ... stuff ... chatObj[key] = value; // ... stuff ... return chatObj; } Then, your other script can do this: on('chat:message', function(msg) { if (msg.type !== "api") { return }; var command = msg.content.split(" ", 1); if (command.toLowerCase() === '!heal') { var chatObj = MasterAPI.processChatMessage(msg); // You are now absolutely certain that everything has happened in the correct order // Also, multiple chat messages coming in at once won't break anything } });
Ah, I gotcha. rather than have MasterAPI catch everything, just have each command run the process to create the chatObj function stored in MasterAPI. Interesting. I do like redundancy, and keeping my API from crashing. I, too, use those "undefined guards" all over a bunch of my scripts, often outputting something like, sendChat("System", "This is wrong, here's why."); return; So I know exactly what's missing to make something break, and then making sure the whole system doesn't fall over because the API is throwing an error. You have taught me many useful things. I shall do my best to not write bad code and bring shame upon your teachings. Hopefully I can go out and make my API more interactive and stable. I don't suppose you know enough about the Powercard script to be able to tell me how to pull int's from inline rolls out of it eh? Might even be worthwhile to make a separate topic for it.
1425476414
The Aaron
Pro
API Scripter
I love topics like this. :) (empty array is also falsey) For powercards, you can't pull values out in all cases, but you could either process !power calls along side powercards, looking for /--Heal\|\$\[\[(\d+)\]\]/ or whatever you use for a heal tag, or you could use the powercard.process() function (or whatever it's called) like a display formatting function. I have a script that uses the command !pcpp to fiddle with a bunch of PowerCard bits before passing them on to the actual powercard function. Btw, if you're looking to write better Javascript, I highly recommend Javascript: the Good Parts by Douglas Crockford. My JS was terrible before I read it. It's a pretty quick read and should teach you all the bits of Javascript you feel uncomfortable with now.
1425477889

Edited 1425478020
Lithl
Pro
Sheet Author
API Scripter
The Aaron said: (empty array is also falsey) No it isn't. Empty array is truthy. > !![] === true true
1425481342
The Aaron
Pro
API Scripter
Brian said: The Aaron said: (empty array is also falsey) No it isn't. Empty array is truthy. > !![] === true true I stand corrected. I must be too used to using it in the context of iteration and getting no iteration. I'll have to be more careful! =D
1425482507

Edited 1425482866
Brian said: The Aaron said: (empty array is also falsey) No it isn't. Empty array is truthy. > !![] === true true Now that's an obscure. I think it simply comes from being non-zero during type coercion so it's a meaningless truth. Brian said: if (!MasterAPI) { // MasterAPI isn't installed, abort return; } Don't do this. This is checking for definition not declaration. To see if it's declared do: if (typeof(MasterAPI) == 'undefined' || !MasterAPI) { return; }
1425484218
The Aaron
Pro
API Scripter
Interesting Ken, I had this distinction crop up in my professional life just yesterday. Injecting jQuery on a client page and preserving the existing definition of $, part of the process is storing the value of $ off. I had something like jqSave = ($ && $.noConflict && $.noConflict(true)) || $; Which kept throwing: Error: $ is undefined to which I head-scratchingly said "yeah, I know that..." Turns out the browser uses the same error for undeclared and undefined, and adding a 'undefined' !== typeof $ before that code resolved the issue. (I believe "use strict"; make referring to an undeclared variable an error.)
The Aaron said: (I believe "use strict"; make referring to an undeclared variable an error.) It would cough up the ghost irregardless. You can't try to eat an apple that doesn't exist. Part of the reason why I'm not a big fan of non-strict languages. Saying ($ && somevar) you're assuming $ exists from which to coerce a boolean. I've been doing JS for only a month now, but language semantics have always intrested me.
1425485315
The Aaron
Pro
API Scripter
Have you read Javascript: The Good Parts by Douglas Crockford? You'd likely enjoy it. He "designed" JSON and writes JSLint. Quite an entertaining speaker too.
1425492201
Lithl
Pro
Sheet Author
API Scripter
Ken L. said: Brian said: The Aaron said: (empty array is also falsey) No it isn't. Empty array is truthy. > !![] === true true Now that's an obscure. I think it simply comes from being non-zero during type coercion so it's a meaningless truth. Brian said: if (!MasterAPI) { // MasterAPI isn't installed, abort return; } Don't do this. This is checking for definition not declaration. To see if it's declared do: if (typeof(MasterAPI) == 'undefined' || !MasterAPI) { return; } Both of those conditions result in true for the exact same set of values. If you only want to check that a variable is undefined and not against other falsey values, it's true that typeof is a better option. However, for the vast majority of use cases, simply coercing the variable to a boolean is more than sufficient.
Brian said: Both of those conditions result in true for the exact same set of values. If you only want to check that a variable is undefined and not against other falsey values, it's true that typeof is a better option. However, for the vast majority of use cases, simply coercing the variable to a boolean is more than sufficient. I'd hate to say this, but it's actually pretty important to make the distinction between declared and defined . At load, this will raise no issues, but during the time of execution, it won't know that the variable is undeclared and will try to reference it and turn up nothing. Using typeof is a form of coercion itself at a more primitive level (at least as far as javascript sees it). Here the case was, if I understand it, that you're checking the existence of a variable as opposed to wither it has a value, which assumed it was declared. you can try the script: <a href="http://jsfiddle.net/odoky47v/" rel="nofollow">http://jsfiddle.net/odoky47v/</a> var a if (b) alert("hello");
1425498342
Lithl
Pro
Sheet Author
API Scripter
I'm still not certain what you think the issue is. In JavaScript, if you try to reference an undeclared variable, the runtime will treat it as a reference to an undefined global variable. If you try to reference an nonexistent property, the runtime will treat it as a reference to an undefined property. In nonstrict contexts, there isn't actually a means to prove that a variable is undeclared as opposed to simply undefined. (In a strict context, referencing an undeclared variable raises an error, so while there remains no means to test for it in your code, it also means that won't cause unforseen problems, as your script will simply crash.)
Brian said: it also means that won't cause unforseen problems, as your script will simply crash. exactly :p Unless you don't mind crashing.