Skip to content
shlainn edited this page Sep 14, 2010 · 1 revision

DefScript is the scripting language PseuWoW uses for scripting events. ”‘Def”’ means “Dynamic extension language”, but dont ask me why its a ”‘f”’ instead on an ”‘l”’. Maybe because ”‘DelScript”’ sounds kinda funny.

DefScript is founded and developed by False.Genesis.

DefScript files mostly end with the file extension .def, and PseuWoW expects them to reside in the “scripts” folder.

It feels a bit like TCL, but also ideas from PHP and C are present.

There is only one datatype, the String, that is used for everything (like its the case in TCL or AutoIt3).

Type conversions are maintained internally if needed.

There are additional datatypes to use, but these are also stored and maintained internally, and get accessed via name placeholders (that are strings anyway) and related functions.

For the preload instructions, similar to C and C++, check out DefScript:Functions

The dynamic datatypes make it possible to modify scripts, variable names and functions during runtime.

DefScript is far from finished; at the current stage of development it can already be used to extend PseuWoW quite a bit.

New functions are added when either requested (check the forum for that) or required in PseuWoW.

FUNCTION,Param1,Param2,... LastParam

FUNCTION: name of the script or function that should be executed. Can either be an internal script or a .def file. Function names are never case sensitive. For a reference of functions head over to the [wiki:DefScript_Reference] page.

”‘Params:”’ Imagine a function call like “say hello”. In this case “say” is the ”‘function”’, and “hello” is the ”‘last param”’, also called ”‘defaultarg”’. Now we can extend this call by adding a language:

say,common hello

Additinal args are appended with commas, as shown above. At the current stage of development, you can use up to 4294967296 (2^32) args.

Be aware the the first space will be interpreted as the beginning of the defaultarg: (desired purpose: whisper “hi there” to player “Keks”)

SENDCHATMESSAGE,6,hi there,Keks

This call is interpreted as “SENDCHATMESSAGE,6,hi” beeing the func/arg list, and “there,Keks” beeing the defaultarg, which would not produce the expected results.

To indicate a contigous string, curly brackets are used:

SENDCHATMESSAGE,6,{hi there},Keks

Spaces and commas can only be used in the argumant list when put in curly brackets, else it may produce unexpected results.

This does not matter for the defaultarg:

whisper,Keks,common blah blah, etc,etc.

The defaultarg will always be interpreted as a contigous sting (because there is nothing to split up).

All variables are internally stored as ”‘Strings”’.

Once set, they remain in memory until they are ”‘unset”’, like ”‘static”’ variables in C++.

set,x 1

Sets the variable ”‘x”’ to ”‘1”’ (like ”‘x = 1”’ in C++)

set,{my message} Hello World!

It is also possible to use spaces or any other chars except ”‘{”’ and ”‘}”’ in variable names.

All variables you use are set in a local scope. Example: script ”‘position.def”’ sets a variable with the name ”‘xyz”’.

The variable will be stored as ”‘position::xyz”’.

An exception to the rule is the following statement, this is how global variables are set:

set,#x 1

”‘#”’ at the beginning of the variable indicates a global variable, so the internal name of the variable will just be ”‘x”’.

All ”‘#”’ and ”‘:”’ at the beginning of variable names are removed.

Since all varibles are static, they need to be removed manually if they are no longer needed or if they should get assinged a new value when the function is called again (check var ”‘lang”’ in ”‘say.def”’ as an example).

Function call:

unset varname

Nothing will happen if the variable didn’t exist or if it has been unset before.

A special kind of variables are macros, which values can only be changed by the program itself.

Macros begin with “@”.

(Note that a call like “set,@macro xyz” will have no effect!)

Check out DefScript:Macros

Have a look at this short example code:

SET,x 1
SET,mystr hello world
OUT ${mystr}, x has the value ${x}
SET,mystr ${mystr} - goodbye
OUT ${mystr}

Output:

hello world, x has the value 1
hello world - goodbye

The parser will convert ”‘${varname}”’ into the variables’ value, and then interpret the lines.

If a variable has not been set but is accessed, no parsing will be done, ${varname} will stay. Example:

out x = ${x}
set,x 123
out x = ${x}

Output:

x = ${x}
x = 123

There is a wrapper function (getvar), that returns the value of a var if its set, and if not, it returns an empty string.

Return values are explained below.

Snippet:

... ?{getvar x}

Global variables are accessed the same way they are set:

set,#x 123
out global x = ${#x}

By interpreting local variables as globals it is even possible to access other private varibles:

#script=position
// var will be stored as "position::xyz"
set,xyz 55 123 94 74

#script=posreset
// output the value of a foreign private variable
out Old postion: ${#position::xyz}
// and change its value
set,#position::xyz 0 0 0 0

Same for accessing macros:

out Mymacro = ${@mymacro}

Return values are similarly accessed like variables, but instead of ”‘$”’ a ”‘?”’ is used.

The function name with its args follows in the bracket:

set,hexval ?{tohex 3735927486}
out ${hexval}
// output: 0xDEADBABE

set,a 1
set,b
out a set: ?{isset a}
out b set: ?{isset b}
out c set: ?{isset c}
out a & b set: ?{and,?{isset a} ?{isset b}}

// output:
// a set: true
// b set: true
// c set: false
// a & b set: true

To return a value from a script, use ”‘return”’ somewhere in the script. When a value is returned,

the current script will be left then, as it is the case in other programming languages.

If no value is returned explicitly at the end of a script, an empty string will be returned.

set,outstr
set,elems ?{lsplit,mylist ${@def}}
set,i ${elems}
loop
    sub,i 1
    if ?{equal,${i} -1}
        exitloop
    endif
    append,outstr ?{lindex,mylist ${i}}
endloop
ldelete mylist
return ${outstr}

All strings with a minimum length of 1 character are interpreted as ”‘true”’, except the ones below. Usually, a simple “true” is used.

An empty string, “0” or “false” are interpreted as ”‘false”’.

Keep in mind that all vars are strings, so “0.0” or “00” will return true also, and that all boolean checks are ”‘case-sensitive”’ - “FALSE” is ”‘true”’, actually!

These Instructions are interpreted when the script is loaded.

They begin with ”‘#”’ followed by an instruction.

Check out DefScript:Preprocessor for a list.

”‘ALL”’ variables, lists, ByteBuffers and files remain in memory and need to be deleted ”‘manually”’!

Different datatype variables can have the same name - having a ByteBuffer, a list and a variable called “x” is no problem for the interpreter.

All variable names can contain spaces and other special chars except ”‘{”’ and ”‘}”’ (see above) and are ”‘case-sensitive”’!!

The “standard” variable. Its value is stores as a string, like mentioned above. Only variables can be accessed with ”‘${varname}”’ They are ”‘static”’, and must be deleted ”‘manually”’.

The are no arrays in traditional means, but it is possible to have multiple vars like “var_1”, “var_2”, etc. Just unsetting the mess can be a pain.

The list datatype is used as a replacement for array, and large amounts of data can be stored in a single list. They can be accessed randomly by an index ”‘“set,x ?{lindex,mylist 5}””’. The first index is ”‘0”’, not ”‘1”’! If an invalid index is accessed, an empty string will be returned. There will be no other indication of an error.

Items can be deleted from a list, added to front, back and somewhere between, erased from all positions, etc.

The underlying data structure is the C++ ”‘std::deque<std::string>”’.

Lists, like variables, remain in memory until they are deleted manually.

The scripts itself are stored in lists, and can be modified like any other list. Only deletion of these lists is not possible, but they can be cleaned. However, cleaning a list of a script that is currently beeing executed (or somewhere else in the call stack) is not a good idea - it will cause iterator invalidation and likely lead to a crash.

The script lists are stored as ”‘#DEFSCRIPT::SCRIPT::<scriptname>”’ (scriptname is always lowercased, rest uppercased!)

Since DefScript is not able to handle binary data in lists or variables, there is the ByteBuffer type, which supports storing and reading variables in/from their value’s binary-representation; strings can be stored too. By using ByteBuffers, network packets and binary files can be handled.

ByteBuffers can also be accessed randomly, but it is not possible to remove or insert bytes at the beginning or in the middle of the container, data can only be appended to the end. Overwriting existing data is possible at every position.

(In case you need to store a 4-byte-integer (uint32) but know its value only after filling the ByteBuffer, you can append 4 null-bytes at the beginning that are later overwritten with the correct value.)

ByteBuffers are the only way to obtain bitmask representations of floats, for example (store as float, read as uint32, etc.)

All file operations are possible with DefScript; text as well as binary files can be written and read, created, seeked and flushed. There is a direct binding to ByteBuffers, so that whole files can be read into a Bytebuffer or a ByteBuffer can be written to a file.

Clone this wiki locally