====== Scripting ====== **Note:** Scripting is a new feature at this point, in early development. The implementation so far is a framework that allows for a breadth of functionality to be implemented, however, the language and features are likely to evolve to meet requirements ; if the scripting language doesn't do something you feel it should, please get in contact with Iain Maltz. ==== Introduction ==== Scripting support in GPHUD is supposed to allow functionality beyond that which exists through existing commands, for example an Armor damage mitigation system that doesn't allow damage to go below 1 point. ==== Language ==== The language used is a C style language (like LSL) and has the following instructions: if ([condition]) { [statements] } ''else { [statements] }'' [type] [variablename] = [expression]; [variablename] = [expression]; while ([condition]) { [statements] } Ten operators exist + (Addition) - (Subtraction) * (Multiplication) / (Divide) == (Equality) != (Inequality) < (Less Than) > (Greater Than) <= (Less Than or Equal to) >= (Greater Than or Equal to) Seven data types exist Character - GPHUD character Avatar - SL Avatar Group - CharacterGroup Response - Result from an API call String - Text string Integer - Whole number (integer) List - Weakly typed list of other data types Two pre-defined variables exist CALLER - refers to the Character that initiated the script AVATAR - the Avatar/User (owner of the character) that initiated the script Some polymorphism exists and works, e.g. 5+"5" will produce "55" (the string), while 5+5 produces the integer 10. Some operations dont make sense, like Avatar + Character and will produce run time errors. Of particular note, the "Response" object, if evaluated as a string (e.g. String message=responseobject) will produce the API call's returned message. Evaluating the Response as an integer produces "0" for no errors and "1" for the response being an error. Lists also can be cast to an Integer which will put the list's size in the Integer. You may also see variables in debug dumps called PC, IC and SUSP ; these are used internally by the virtual machine to store state, are initialised at the point the VM is suspended, and are restored before the VM is resumed. They are of no practical use to the end user and are inaccessible through the programming language (as their real variable names start with a space), however, they may be displayed during debug runs of scripts. Lists are accessible using standard [] methods, such as List sample=["One!","Two","Three"]; sample[0]="One"; sample[1]=sample[1]+"Two"; Note that lists are not strongly typed - you can mix anything inside a List - Integers and Strings in the same List, and you should take care to make sure the types are as you (or the function you're calling) are as expected. Nested lists are not currently supported. ==== Limits ==== Source script: Maximum 65535 lines of up to 65535 columns (16 bit values in Debug instruction) String: Maximum length 65535 (16 bit size in bytecode) Execution cycles: 10,000 bytecode instructions (arbitary limit) ==== Function Calls ==== There are some function calls available, an [[https://sl.coagulate.net/GPHUD/introspection/gsfunctions|up to date list is available via introspection]]. These generally take one or more parameters and always return a single variable, which may be discarded. E.g. this calls gsSayToChar and captured the result in the integer variable useless Integer useless=gsSayToChar(CALLER,"Hello caller"); However one can also just discard the result by calling gsSayToChar(CALLER,"Hello caller"); Since gsSayToChar always returns the useless response of the integer 0, this second form is easier to use. (( Footnote : this wasn't always how it worked in GSScripting which is why we're explicitly stating something most people would assume from other languages, prior to April 2022 returned variables had to be caught with an assignment )) The most expansive of the function calls is gsAPI which allows the script to run any API command that isn't an alias (e.g. ''Health.healRoll'' or whatever). The return from this function is of a unique type, a "Response", which corresponds to the response the HUD normally gives when the command is invoked - e.g. for healroll it would return a message about how much healing was done to the caller. If a response is used as a string, its message is returned. If a response is used as an integer (e.g. if (response==0)) then the number 0 refers to success, and 1 means the call errored. ==== Custom Function Calls ==== You can use this same "function calling" syntax to call another script. Note that variables are all GLOBAL and shared between scripts that call each other. A script may also "return" an expression, e.g. return "String"; or return 5+5; . You can also just call return; in which case it returns an integer of zero. As example: Create a script called askQuestion questions=questions+1; return gsGetText(CALLER,"Input some text"); Create another script called test
Integer questions=0;
String response1=askQuestion();
String response2=askQuestion();
Integer r=gsSayAsHUD(CALLER,"Asked "+questions+" questions, got "+response1+" and "+response2);

Then, when you run "test", it will load and call the other script twice, and produce appropriate output, e.g.:
GPHUD: Asked 2 questions, got test1 and test2

Note:  You can not call scripts that were compiled before this change was implemented (due to those scripts using absolute addressing, and newly compiled scripts using relative addressing).  You can resolve this issue by simply recompiling your existing target script.

==== Character Creation ====
Normally the HUD presents a very simple set of choices to fill out mandatory fields on the character sheet and so forth.

It may be desirable to have a script run to guide the user through this, or to provide more complex logic (see the example script later).

There is a KV called ''Instance.CharInitScript'' which causes a script to be run **before** the usual character initialisation steps.

**NOTE:** it is very important you code this script carefully ; messing it up will prevent both logins and character creation - this script is always invoked.

  * Scripts can call gsGetChoice, gsGetText and so on to interact with a character
  * Scripts should use gsAPI to call "characters.initialise" with the parameters [attributename,attributevalue], both of type String.  This will allow values to be set that can not be normally set by users.
  * Scripts '''MUST check if the values are already set''' - do not blindly code queries to the user, you should instead check the current value, and if missing, THEN and only then prompt the user. (see note below, see example script further down)
  * Any values that are 'required' attributes but the script doesn't configure will be handled by the "usual" character setup code (i.e. what would happen if you had no script)  (once the script cleanly exits)

Note about "checking if values are already set" - If the character initialisation script "finishes" without querying the user for any input, then the login will proceed normally and complete.  For technical reasons (and the fact the login code needs rewriting some day), if any user interaction is done (getString, getChoice, etc) then the character's login will be restarted from scratch - this means if you ALWAYS ask a question in your startup script, the user will be trapped in an infinite loop of running the startup script over and over.  For an already set up character, your script should check values and exit, not query the user for anything.

[[Example Scripts|See here for example scripts]]

==== Polymorphism ====