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] API command process, standard model.

1384095280
Stephen S.
Pro
Marketplace Creator
Sheet Author
API Scripter
This is based on Alex L suggestion of a standard API chat processes... and suggestions/practices I have seen by others. I am trying to keep the code very readable and straightforward so I can understand it. Input Example: /br 1d100+20 to hide in shadows Output Example logged: "Description: Blind roll to GM." "Type: Player" "Long: broll" "Short: br" "Family: common" "message: 1d100+20 to hide in shadows" "FirstName: Stephen" "OwnerSent: true" "GM_Roster:-J7zZWqo-jGZTHVm6frY" "GM: true" "Playerid: -J7zZWqo-jGZTHVm6frY" "Userid: 135636" "Dice: 1d100+20" Commands can be added in standard format: roll20API.apiCommands = [ //Player commands, common {Description: "Blind roll to GM.", Type: "Player", Long: "broll", Short: "br", Family: "common"}, {Description: "API help menu.", Type: "Player", Long: "help", Short: "h", Family: "common"}, //Family commands, language {Description: "Speak in kender.", Type: "Player", Long: "kender", Short: "k", Family: "language"}, {Description: "Speak in dwarven.", Type: "Player", Long: "dwarven", Short: "d", Family: "language"}, {Description: "Speak in elven.", Type: "Player", Long: "elven", Short: "e", Family: "language"}, {Description: "Speak in orcish.", Type: "Player", Long: "orish", Short: "o", Family: "language"}, //GM commands, common {Description: "Fully heal all targets.", type: "GM", Long: "full", Short: "f", Family: "common"}, //Owner commands, common {Description: "See player ids.", type: "Owner", Long: "ids", Short: "ids", Family: "common"} ]; Each command has description, type of player that can use it, long and short format and if its a common command or part of a family of commands (this way all commands of one family can be processed the same.) , Owner commands belong to the campaign owner: ( Brian inspired) //***roll20API.Owner = "135636"*** //Campaign Owner. You can find your own personal user id by visiting the wiki and clicking on your name in the //left-hand sidebar. On your wiki page you will see "Home » User:#" below your name on your userpage, where # //is your user id. GM_Roster (Because Brian thinks all players are sneaky rascals that will place " (GM)" in their display name.) //Check for GM status based on handout named "GM_Roster" roll20API.GM_Roster = findObjs({ _type: "handout", name: "GM_Roster" })[0].get("controlledby").split(","); if(roll20API.GM_Roster.indexOf(roll20API.Playerid) == -1){ roll20API.GMsent = false; }else{ roll20API.GMsent = true; }; (also useful for know who all the current GMs are.) Any Dice Roll //Dice of the message if(roll20API.message !== null){ try{ var parts = roll20API.message.toLowerCase().split(' '); sendChat('', parts[0], function(outs) { // outs[0] is a message object containing the results of the die roll in parts[0] // This sendChat message will NOT appear in the actual chat window }); roll20API.Dice = parts[0]; } catch(e){ roll20API.Dice = undefined; } }else{ roll20API.Dice = undefined; }; Notes on display names //NOTES: // //***Display Names*** //Display Names should be one word, no spaces or special characters and distinct. // Finally DRAFT of the code. var roll20API = roll20API || {}; //NOTES: // //***Display Names*** //Display Names should be one word, nospaces or special characters and distinct. // //***roll20API.Owner = "135636"*** //Campaign Owner. You can find your own personal user id by visiting the wiki and clicking on your name in the //left-hand sidebar. On your wiki page you will see "Home » User:#" below your name on your userpage, where # //is your user id. // //GM Roster //Create a handout named "GM_Roster" and in the "Cn Be Edited By" field place all the names of the GMs for the //campaign. Keep current as required. //campaign Owner roll20API.Owner = "135636"; //API Command variables roll20API.apiCommands = [ //Player commands, common {Description: "Blind roll to GM.", Type: "Player", Long: "broll", Short: "br", Family: "common"}, {Description: "API help menu.", Type: "Player", Long: "help", Short: "h", Family: "common"}, //Family commands, language {Description: "Speak in kender.", Type: "Player", Long: "kender", Short: "k", Family: "language"}, {Description: "Speak in dwarven.", Type: "Player", Long: "dwarven", Short: "d", Family: "language"}, {Description: "Speak in elven.", Type: "Player", Long: "elven", Short: "e", Family: "language"}, {Description: "Speak in orcish.", Type: "Player", Long: "orish", Short: "o", Family: "language"}, //GM commands, common {Description: "Fully heal all targets.", type: "GM", Long: "full", Short: "f", Family: "common"}, //Owner commands, common {Description: "See player ids.", type: "Owner", Long: "ids", Short: "ids", Family: "common"} ]; on("chat:message", function(msg) { //Return if it s not an API command if(msg.type !== "api"){return}; //parse the message or flag as null if(msg.content.indexOf(' ') == -1){ roll20API.message = null; roll20API.command = msg.content.substr(1, msg.content.length); }else{ roll20API.message = msg.content.substr(msg.content.indexOf(' ') + 1); roll20API.command = msg.content.substr(1, msg.content.indexOf(' ')-1); }; //Cleans off "(GM)" if (msg.who.indexOf(" (GM)") !== -1){roll20API.Who = msg.who.substr(0,msg.who.length - 5);}; //Get first name of player only (need for sending wishpers) if(roll20API.Who.indexOf(' ') == -1){ roll20API.FirstName = roll20API.Who; }else{ roll20API.FirstName = roll20API.Who.substr(0,roll20API.Who.indexOf(' ')); }; //PlayerID roll20API.Playerid = msg.playerid; //Check for GM status based on handout named "GM_Roster" roll20API.GM_Roster = findObjs({ _type: "handout", name: "GM_Roster" })[0].get("controlledby").split(","); if(roll20API.GM_Roster.indexOf(roll20API.Playerid) == -1){ roll20API.GMsent = false; }else{ roll20API.GMsent = true; }; //UsedID roll20API.Player = getObj('player', msg.playerid); roll20API.Userid = roll20API.Player.get('d20userid'); //Is Campaign Owner if(roll20API.Userid == roll20API.Owner){ roll20API.OwnerSent = true; }else{ roll20API.OwnerSent = false; } //Dice of the message if(roll20API.message !== null){ try{ var parts = roll20API.message.toLowerCase().split(' '); sendChat('', parts[0], function(outs) { // outs[0] is a message object containing the results of the die roll in parts[0] // This sendChat message will NOT appear in the actual chat window }); roll20API.Dice = parts[0]; } catch(e){ roll20API.Dice = undefined; } }else{ roll20API.Dice = undefined; }; roll20API.Description = "API help menu."; roll20API.Type = "Player"; roll20API.Long = "help"; roll20API.Short = "h"; roll20API.Family = "common"; _.each(roll20API.apiCommands, function(indexCommands) { if(indexCommands.Long == roll20API.command || indexCommands.Short == roll20API.command){ roll20API.Description = indexCommands.Description; roll20API.Type = indexCommands.Type; roll20API.Long = indexCommands.Long; roll20API.Short = indexCommands.Short; roll20API.Family = indexCommands.Family; }; }); log("~~~~~~~~~~~~~~~"); log("Description: " + roll20API.Description); log("Type: " + roll20API.Type); log("Long: " + roll20API.Long); log("Short: " + roll20API.Short); log("Family: " + roll20API.Family); log("message: " + roll20API.message); log("FirstName: " + roll20API.FirstName); log("OwnerSent: " + roll20API.OwnerSent); log("GM_Roster:" + roll20API.GM_Roster); log("GMsent: " + roll20API.GM); log("Playerid: " + roll20API.Playerid); log("Userid: " + roll20API.Userid); log("Dice: " + roll20API.Dice); });
1384103329
Stephen S.
Pro
Marketplace Creator
Sheet Author
API Scripter
Here is an update with "switch" placeholders to navigate any number of commands.... I am sure there is a more elegant way to switch based on command type and family. var roll20API = roll20API || {}; //NOTES: // //***Display Names*** //Display Names should be one word, nospaces or special characters and distinct. // //***roll20API.Owner = "135636"*** //Campaign Owner. You can find your own personal user id by visiting the wiki and clicking on your name in the //left-hand sidebar. On your wiki page you will see "Home » User:#" below your name on your userpage, where # //is your user id. // //GM Roster //Create a handout named "GM_Roster" and in the "Cn Be Edited By" field place all the names of the GMs for the //campaign. Keep current as required. //campaign Owner roll20API.Owner = "135636"; //API Command variables***************************************************************************** roll20API.apiCommands = [ //Player commands, common {Description: "Blind roll to GM.", Type: "Player", Long: "broll", Short: "br", Family: "common"}, {Description: "API help menu.", Type: "Player", Long: "help", Short: "h", Family: "common"}, //Family commands, language {Description: "Speak in kender.", Type: "Player", Long: "kender", Short: "k", Family: "language"}, {Description: "Speak in dwarven.", Type: "Player", Long: "dwarven", Short: "d", Family: "language"}, {Description: "Speak in elven.", Type: "Player", Long: "elven", Short: "e", Family: "language"}, {Description: "Speak in orcish.", Type: "Player", Long: "orish", Short: "o", Family: "language"}, //GM commands, common {Description: "Fully heal all targets.", type: "GM", Long: "full", Short: "f", Family: "common"}, //Owner commands, common {Description: "See player ids.", type: "Owner", Long: "ids", Short: "ids", Family: "common"} ]; //API:Events**************************************************************************************** on("ready", function() { //API:Events:Add Character********************************************************************** on("add:character", function(addedChar) { sendChat("API", "Add Character Event place holder"); }); //API:Events:ChatMessage************************************************************************ on("chat:message", function(msg) { if(msg.type == "api"){ roll20API.processMessage(msg); roll20API.processAPIswitch(); }; }); }); //API:Events:ChatMessage:processAPIswitch*********************************************************** roll20API.processAPIswitch = function(msg) { sendChat("API", "~~~~~~~~~~~~~"); sendChat("API", "roll20API.Family = " + roll20API.Family); sendChat("API", "roll20API.Long = " + roll20API.Long); //Player common command switch if(roll20API.Family == "common" && roll20API.Type == "Player"){ switch (roll20API.Long){ case "help": sendChat("API", "Help Command"); break; case "broll": sendChat("API", "Broll Command"); break; default: sendChat("API", "Default Command"); break; }; }; //GM common command switch if(roll20API.Family == "common" && roll20API.GM == true){ switch (roll20API.Long){ case "full": sendChat("API", "full Command"); break; default: sendChat("API", "Default Command"); break; }; }; //Owner common command switch if(roll20API.Family == "common" && roll20API.OwnerSent == true){ switch (roll20API.Long){ case "ids": sendChat("API", "ids Command"); break; default: sendChat("API", "Default Command"); break; }; }; //Switch based on family if(roll20API.Family !== "common"){ switch (roll20API.Family){ case "language": sendChat("API", "language Command"); break; default: sendChat("API", "Default Command"); break; }; }; }; //API:Events:ChatMessage:processMessage************************************************************* roll20API.processMessage = function(msg) { //Output Example //-------------------------------- //"roll20API.Description: Blind roll to GM." //"roll20API.Type: Player" //"roll20API.Long: broll" //"roll20API.Short: br" //"roll20API.Family: common" //"roll20API.message: 1d100+20 to hide in shadows" //"roll20API.FirstName: Stephen" //"roll20API.OwnerSent: true" //"roll20API.GM_Roster:-J7zZWqo-jGZTHVm6frY" //"roll20API.GM: true" //"roll20API.Playerid: -J7zZWqo-jGZTHVm6frY" //"roll20API.Userid: 135636" //"roll20API.Dice: 1d100+20" //Return if it s not an API command if(msg.type !== "api"){return}; //parse the message or flag as null if(msg.content.indexOf(' ') == -1){ roll20API.message = null; roll20API.command = msg.content.substr(1, msg.content.length); }else{ roll20API.message = msg.content.substr(msg.content.indexOf(' ') + 1); roll20API.command = msg.content.substr(1, msg.content.indexOf(' ')-1); }; //Cleans off "(GM)" if (msg.who.indexOf(" (GM)") !== -1){roll20API.Who = msg.who.substr(0,msg.who.length - 5);}; //Get first name of player only (need for sending wishpers) if(roll20API.Who.indexOf(' ') == -1){ roll20API.FirstName = roll20API.Who; }else{ roll20API.FirstName = roll20API.Who.substr(0,roll20API.Who.indexOf(' ')); }; //PlayerID roll20API.Playerid = msg.playerid; //Check for GM status based on handout named "GM_Roster" roll20API.GM_Roster = findObjs({ _type: "handout", name: "GM_Roster" })[0].get("controlledby").split(","); if(roll20API.GM_Roster.indexOf(roll20API.Playerid) == -1){ roll20API.GMsent = false; }else{ roll20API.GMsent = true; }; //UsedID roll20API.Player = getObj('player', msg.playerid); roll20API.Userid = roll20API.Player.get('d20userid'); //Is Campaign Owner if(roll20API.Userid == roll20API.Owner){ roll20API.OwnerSent = true; }else{ roll20API.OwnerSent = false; } //Dice of the message if(roll20API.message !== null){ try{ var parts = roll20API.message.toLowerCase().split(' '); sendChat('', parts[0], function(outs) { // outs[0] is a message object containing the results of the die roll in parts[0] // This sendChat message will NOT appear in the actual chat window }); roll20API.Dice = parts[0]; } catch(e){ roll20API.Dice = undefined; } }else{ roll20API.Dice = undefined; }; roll20API.Description = "API help menu."; roll20API.Type = "Player"; roll20API.Long = "help"; roll20API.Short = "h"; roll20API.Family = "common"; _.each(roll20API.apiCommands, function(indexCommands) { if(indexCommands.Long == roll20API.command || indexCommands.Short == roll20API.command){ roll20API.Description = indexCommands.Description; roll20API.Type = indexCommands.Type; roll20API.Long = indexCommands.Long; roll20API.Short = indexCommands.Short; roll20API.Family = indexCommands.Family; }; }); };
1384180164

Edited 1384180301
Not to discourage the work you're doing here, but you might aim to decouple the API commands from how they are processed. The way my apicmd system works is to provide a method to register new commands, along with the available options and rules, from a second script. Using such a technique, I'm able to provide the same global help functionality while only requiring othe scripts use my apicmd.on function instead of an on(chat) handler. When developing a framework, you or others should be able to add modules without having to modify existing code. That's an objective of decoupling, by providing a standard interface others can contribute by building modules that use your code without worrying that your updates will break it since the interface won't change. This has the handy benefit of making it easier for you to develop in a modular form. Ask yourself "how can this code be used by others without having to make modifications?" So instead of having an array of hardcoded commands provide a method by which others can register commands in the array. I will be uploading my implementation tonight. It is heavily based on OptParse to support command line style flags and options. Commands are registered by other modules wishing to use the standardized command processing, and they in turn receive an object containing the flags, options, and arguments passed in chat.
1384182675
Stephen S.
Pro
Marketplace Creator
Sheet Author
API Scripter
LOL please DISCOURAGE! Discouraging will save me hours and hours! I know enough about javascript to entertain me, but not enough to be effective or efficient at writing code. I tend to go back to my "Vic 20" roots (yea... I am that freaken old) and write in a very "if then" way. I know what I want... but to get from my pinky finger to my thumb, I am sure I am going there by way of my elbow. I think I am likely like a lot of users and find the feedback from you and other EXTREMELY valuable... so don't spare my feelings and always suggest a better path!
I am encouraged to see dialogue, I am not a coder, but a standardized framework is essential. I really want to be optimistic that our experts in this community will also see the value and contribute, advice, frameworks, etc...
1384256111
Stephen S.
Pro
Marketplace Creator
Sheet Author
API Scripter
This is great! This is what your "all" in one needs.
1384258677

Edited 1384259329
That is great, this is starting to certainly take shape! I copied John's code to my thread as well.