*** BuildScript, a scripting language for Mapster32 *** BuildScript is a scripting language for Mapster32 that allows you to access certain structures of a BUILD map from the level editor at runtime. 0. Quickstart ------------- If you don't feel like reading all this, do the following: a. read the next section b. examine the provided example files, a.bs, b.bs and bs_tut.map c. Take a look at bssynhlp.h for the accessible BUILD vars/structure members/arrays/functions and their shorthands. It also has a bit of explanation on them. 1. Interface in Mapster32 ------------------------- The interface is via the command line in the console (~ key). The following commands are added: bs : parses BuildScript file do : executes BuildScript statement in place def (params,...) {function body}: define BuildScript function run [params...]: runs function in BuildScript interpreter (params are seperated by spaces) reset: resets BuildScript machine (after a runtime error occurs, the BS machine halts) CAUTION: when using `do' or `def' interactively, you need to write the apostrophe character (') whenever you want a semicolon. This is because the OSD uses the semicolon as a command delimiter. Additionally, since you cannot type the tilde (~) in the console, the dollar sign ($) is an alias for it. 2. BuildScript language ----------------------- BuildScript features C-like syntax, so that even functions taken from the BUILD/mapster32 source code should work with minor modifications (provided the structures in question are accessible to BuildScript, and the code doesn't contain constructs not recognized by BuildScript (such as pointers)). Expressions should be parsed as in C (with exceptions, see below), since it's based on the same grammar. A BuildScript file is a sequence of function declarations or definitions. In interactive BuildScript (in Mapster32), you can also execute statements in place with the `do' command. The code following the `do' is automatically surrounded by braces, so it always parses as a compound statement. You declare a function like this: func add4(q,w,e,r); and define it like this: def add4(q,w,e,r) { return q+w+e+r; } (Funtion declarations are rarely needed, and you can achieve the same effect with defining an empty function with the same name and signature first, and redefine it later.) Once you have declared or defined a function, you can redefine it os often as you wish, but you may not use a different number of parameters in the new definition, as existing code might already use the function. Declaration of local variables is with `var' or `int' (both do the same, but `int' is preferred). The only type of number in BuildScript is the 32 bit wide, signed integer. There are four types of "named things" in BuildScript: variables, buildvars, the three main build map structures, and BUILD arrays. Variables are declared by the user and can be written to at any time. Buildvars are variables of the editor (like the current x position), some of them writable. The structure members of the three main build map structures sprite, wall and sector are accessible, and some of them are writable. (The read-only ones are those that would very likely corrupt the map if altered.) Also, some useful arrays like highlight[] are accessible. The ones that are used by the editor are read-only. Additionally, eight writable arrays named ar1 thru ar8 are provided for the user, each one having size 16384. All arrays have global scope and refer to the same memory (respectively) at any time. Lastly, BuildScript provides access to some high-level BUILD functions. They cannot be redefined. Many buildvar, structure member, and array names have shorthand forms for interactive use. (Use in scripts is allowed, but discouraged, with the exception of sin[] and cos[].) While on the surface BuildScript looks very much like C, it is only a small subset (plus a few additions not in C), and differs in several ways (the list is not exhaustive): - no preincrement/predecrement operators; the post- versions work on variables only - no switch/case statement - The break/continue statements feature an optional depth parameter which specify which loop should be broken/continued. A value of 0 means "innermost loop", incrementing it goes to outer loops. - there is an operator `print', with precedence on the same level as unary operations (thus, "print a+2" is an expression that evaluates to a+2, and prints the value of `a' as a side effect) - Logical expressions are always evaluated fully, even if the outcome is already decided. This is in contrast to C, where in the expression "(0 && dosomething())", dosomething() would never be executed. - there are no `void' functions as such. Functions that end in a "return;", or reach the end without a return statement, do return a 0. - BuildScript features "for (i in ...)" constructs. The iterable is declared automatically. Don't use variables named _n (n a number) inside this. 3. Example session (// mark comments) ------------------ bs a // load a.bs // (select some sectors) run upscale 2 // scale selected sectors by 2 // (go to 3d mode, point at a sprite) do sprite[searchwall].picnum=SHIELD' // note the apostrophe instead of ';'! // do sp[swal].pn=SHIELD' would do the same // suppose you want to change the tile of all parallaxed skies // (usually, you need to reload the map after that) def chsky(pic) {for(i in sectors) if (sector[i].ceilingstat&1) sector[i].ceilingpicnum=pic'} // def chsky(pic) {for(i in sectors) if (se[i].cst&1) se[i].cpn=pic'} is the same // now you can use it: run chsky 90 quit 4. Looping constructs --------------------- These are strewn in the BUILD/Mapster32 source all over the place, and are distilled here for convenience. They are accessible with the much more convenient "for (i in ...)" forms; the long form is roughly the expansion produced. (The "for (i in ...)" feature uses textual substitution.) LOOPS OVER SPRITES ~~~~~~~~~~~~~~~~~~ all sprites in the map: for (s in sprites) for (s=0; s=0; sp=nextspritesect[sp]) LOOPS OVER WALLS ~~~~~~~~~~~~~~~~ all walls in the map: for (w in walls) for (w=0; w