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.

November 10 (11 years ago)
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);
});




November 10 (11 years ago)
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;
};
});
};

November 11 (11 years ago)

Edited November 11 (11 years ago)
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.
November 11 (11 years ago)
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!
November 12 (11 years ago)
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...
November 12 (11 years ago)
Stephen S.
Pro
Marketplace Creator
Sheet Author
API Scripter
This is great!

This is what your "all" in one needs.
November 12 (11 years ago)

Edited November 12 (11 years ago)
That is great, this is starting to certainly take shape! I copied John's code to my thread as well.