So I said that I would create a post with more details about the JavaScript functions etc. But I had to make sure I could add some JavaScript functions and get all of that working and due to the flu I wasn't able to get it out as quickly as I would have liked, but better late than never
So firstly what do the functions look like in the script (which from now on I will refer to as RPTools Script so no one thinks I am talking about JavaScript). All of the stuff described in this post works in the latest code in the git repository.
If you make it through the original post and this post you will probably notice that RPTools doesn't seem to have much in the way of looping, its not something that you have missed there isn't much. The intention is to push as much of the coding as possible down to the JavaScript level, RPTools is really only for really simple stuff. Anyway, onwards!
Either Java or JavaScript can export and make available functions to RPTools Script, I will really only detail the JavaScript definition of functions in this post as thats what most people are going to be more interested it, and to be honest the Java part is a lot more straight forward so if you can understand the JavaScript part looking at the Java exported functions in git its dead easy to see how to create a function.
To call a function with no parameters not surprisingly its something like the following
Arguments can either be passed by position or by name (or a mixture as long as all the named parameters come after the non named parameters).
So for example if we had a function by the name of rollSomeDice(num, sides) that rolls a number of dice all of the following are equivalent.
Code: Select all
[rollSomeDice(2, 6)]
[rollSomeDice(2, sides: 6)]
[rollSomeDice(num: 2, sides: 6)]
[rollSomeDice(sides: 6, num: 2)]
The order of the named arguments in the call don't matter (otherwise there would not be much point in having named parameters).
To support this each JavaScript function that you write that will be exported will accept a single argument. This argument will be a JavaScript object that contains each of the parameters, so for the above say your JavaScript function was defined as
Then inside the function args would look like
Except of course it would be a JavaScript object not text. So you examine the arguments, roll the requisite number of dice and return the result. Thankfully the RPTools scripting engine takes care of conversions between the types it knows about and the types JavaScript knows about (in most cases anyway, there are sure to be some odd corner cases where you may have to tell JavaScript this is actually a number not the string "2" before returning it if it is inside a list or dictionary).
When exporting a function you will need to tell the scripting engine what parameters it accepts, the data types of these parameters, any default values the parameters may have and the return data type of the function. These are all defined in terms of the RPTools script type not the JavaScript type. When the function is called the engine will attempt to match up all the parameters and then convert the values to what is expected, so if you pass 1.4 to a function that expects and integer value it will be truncated to 1, the script engine is pretty aggressive about conversion so it will convert numbers to strings or even single values to a list to match the function definition. Likewise when the function returns a value the script will convert that value into the value it expects.
The conversion between types is detailed below.
Code: Select all
RPTools Script type JavaScript Type
Long Number
Double Number
List JavaScript Array
Dictionary JavaScript Object
Boolean boolean
String String
Result Java Object (Result object)
Null null
Any
Null is mostly used when defining default values for function parameters, Any has no mapping in JavaScript and is only used to represent a function that can return any data type, in this case the engine will make a "best guess" at what type of value it is.
All parameters that do not have a default value are mandatory.
Probably the easiest way to show how to export a function is to write a JavaScript file that does just that.
We can export the doRollSomeDice() function with the following JavaScript code
Code: Select all
var rollFunc = new ExportedFunction("rollSomeDice", ExportedFunction.DATA_TYPE_LONG, "doRollSomeDice");
rollFunc.addParameter("num", ExportedFunction.DATA_TYPE_LONG);
rollFunc.addParameter("sides", ExportedFunction.DATA_TYPE_LONG);
rollFunc.export();
delete rollFunc; // Delete the object as we no longer need it.
The ExportedFunction() constructor expects the name of the function as it will be exported to RPTools script, the return data type and the name of the function in the JavaScript code (this cant be in a new scope it has to be in the main scope of the script ie an object method, but each script/group of scripts are run in a scope of its own). All of this would go in the same script so for our first go
Code: Select all
function doRollSomeDice(args) {
var times = args.num;
var sides = args.sides;
var res = 0;
while (times--) {
res += rand(sides);
}
return res;
}
var rollFunc = new ExportedFunction("rollSomeDice", ExportedFunction.DATA_TYPE_LONG, "doRollSomeDice");
rollFunc.addParameter("num", ExportedFunction.DATA_TYPE_LONG);
rollFunc.addParameter("sides", ExportedFunction.DATA_TYPE_LONG);
rollFunc.export();
delete rollFunc; // Delete the object as we no longer need it.
The rand() function returns a number between 1 and its argument (and will be improved with a proper random function in the near future).
And this works for the example calls at the top of the script, but it has a problem we want to be able to just roll a single dice with either of the following
But doing either of these will give us an error as num is not provided to the function. To allow for this we can add a default parameter to num of 1.
Code: Select all
function doRollSomeDice(args) {
var times = args.num;
var sides = args.sides;
var res = 0;
while (times--) {
res += rand(sides);
}
return res;
}
var rollFunc = new ExportedFunction("rollSomeDice", ExportedFunction.DATA_TYPE_LONG, "doRollSomeDice");
rollFunc.addParameter("num", ExportedFunction.DATA_TYPE_LONG, 1);
rollFunc.addParameter("sides", ExportedFunction.DATA_TYPE_LONG);
rollFunc.export();
delete rollFunc; // Delete the object as we no longer need it.
Now the above will work, but it could be better, after all it only returns a number what if we also want to know what the rolls were (for tool tips or what have you). You can do this by returning a Result which contains a value, a detailed explanation (e.g. "2 + 4" as a string) and a list of the individual rolls.
Code: Select all
function doRollSomeDice(args) {
var times = args.num;
var sides = args.sides;
var res = 0;
var ivals = [];
while (times--) {
var roll = rand(sides);
res += roll;
ivals.push(roll);
}
var details = arrayAsString(ivals, " + ");
return new Result().setValue(res).setDetails(details).setIndividualValues(ivals);
}
var rollFunc = new ExportedFunction("rollSomeDice", ExportedFunction.DATA_TYPE_RESULT, "doRollSomeDice");
rollFunc.addParameter("num", ExportedFunction.DATA_TYPE_LONG, 1);
rollFunc.addParameter("sides", ExportedFunction.DATA_TYPE_LONG);
rollFunc.export();
delete rollFunc;
The arrayAsString() function above will just format the array as a string with the provided delimiter (so something like "1 + 4").
You could also return the following
Code: Select all
return { value: res, details: details, individual: ivals };