$Id: VavoomC.htm,v 1.3 2002/06/14 15:53:56 dj_jl Exp $
int a; // Declare an integer variable named "a". float f; // Declare a floating-point variable named "f". int Table[64]; // Declare an array of 64 integers named "Table". int *p; // Declare a pointer to int named "p". string PlayerName; // Declare a string pointer. Actor Other; // Declare a variable referencing an actor.Variables can appear in three kinds of places in VavoomC: global variables, which are accessible from everywhere. Instance variables, which apply to an entire object, appear immediately after the class declarations. Local variables appear within a function, and are only active while that function executes.
Here are the basic variable types supported in VavoomC:
int MyArray[20]; // Declares an array of 20 ints.VavoomC supports multidimensional arrays.
int *p; // A pointer to integer.The variable "p" above is a pointer to an integer. Pointers to structs or classes can refer to any object that belongs to a subclass of this struct or class.
There's a special pointer constant NULL which points to "nowhere".
Pointers of type void* also are handled specially - any pointer can be assigned to void* and void* can be assigned to any pointer.
Actor A; // An actor reference.The variable "A" above is a reference to an object in the Actor class. Such a variable can refer to any object that belongs to a subclass of Actor.
When you have a variable that refers to an actor, you can access that actor’s variables, and call its functions.
Variables that refer to actors always either refer to a valid actor (any actor that actually exists in the level), or they contain the value "none". none is equivalent to the C/C++ "NULL" pointer.
Note that an object or actor reference "points to" another actor or object, it doesn’t "contain" an actor or object. The C equivalent of an actor reference is a pointer to an object.
Here is sample code that declares enumerations.
// Declare an enumeration, with three values. enum { CO_Red, CO_Green, CO_Blue };
You can declare a struct as follows:
// A structure describing a plane struct TPlane { TVec normal; float dist; int __type; int __signbits; int __reserved1; int __reserved2; };In VavoomC structures can have a parent structure, just like classes. For example:
struct sec_plane_t:TPlane { float minz; float maxz; int pic; int __base_pic; float xoffs; float yoffs; int flags; int translucency; };
Once you declare a struct, you are ready to start declaring specific
variables of that struct type:
// Declare a pointer variable of type TPlane. sec_plane_t *floor;To access a component of a struct, use code like the following.
void MyFunction(void) { // Scroll texture floor->xoffs += 8.0; floor->yoffs += 4.0; // Pass floor to a function. SomeFunction(floor); }
class MyClass:MyParentClass // Class specifiers. { // Declaration of class variables and functions goes here }Here I am declaring a new class named "MyClass", which inherets the functionality of "MyParentClass".
Object is the parent class of all objects in Vavoom. Object is an abstract base class, in that it doesn’t do anything useful.
Each class inherets all of the variables and functions from its parent class. It can then add new variable declarations, add new functions (or override the existing functions).
The class declaration can take several optional specifiers that affect the class:
struct sec_plane_t;
class MyClass;
void Test(void) { int i; float f; string s; name n; TVec v, q; i = 10; // Assign a value to integer variable i. f = 2.7; // Assign a value to floating-point variable f. s = "Hello!"; // Assign a value to string variable s. n = 'John'; // Assign a value to name variable n. v = q; // Copy value of vector q to v. }VavoomC is strongly typed language, that means that attempts to assign a value of incompatible type will result in compiler error.
In VavoomC, you can declare new functions and write new versions of existing functions. Functions can take one or more parameters, and can optionally return a value. The parameter and return value type mus be of size 4 (i.e. integers, floats, pointers, references) or vectors. Some functions are implemented in C++, they are called builtin functions.
Here are some simple function declarations:
float fabs(float val) { return (val < 0.0) ? -val : val; } class MyClass:MyParentClass { int MyVariable; int GetMyVariable(void) { return MyVariable; } } class SomeOtherClass:SomeOtherBase { int OtherVariable; int GetOtherVariable(void); } int SomeOtherClass::GetOtherVariable(void) { return OtherVariable; }
When a function is called, the code within the brackets is executed.
Inside the function, you can declare local variables, and execute any VavoomC
code. The optional "return" keyword causes the function to immediately
return a value.
WARNING! Local variables you declare in a function are not initialized.
Function calls can be recursive. For example, the following function computes the factorial of a number:
// Function to compute the factorial of a number. int Factorial(int Number) { if (Number <= 0) return 1; else return Number * Factorial(Number - 1); }
float fabs(float val); class MyClass:MyParentClass { int MyFunction(void); }
To override a function, just cut and paste the function definition from the parent class into your new class. For example, for OnMapSpawn, you could add this to your Demon class.
// New Demon class version of the OnMapSpawn function. void OnMapSpawn(mthing_t *mthing) { // If monsters are disabled, then destroy this actor immediately if (nomonsters) { RemoveMobjThinker(this); return; } // Call parent class version of OnMapSpawn ::OnMapSpawn(mthing); }Function overriding is the key to creating new VavoomC classes efficiently. You can create a new class that expands on an existing class. Then, all you need to do is override the functions which you want to be handled differently. This enables you to create new kinds of objects without writing gigantic amounts of code.
native float sin(float angle);
// Example of "for" loop. void ForExample(void) { int i; print("Demonstrating the for loop"); for (i = 0; i < 4; i++) { print("The value of i is %d\n", i); } print("Completed with i=%d\n", i); }The output of this loop is:
Demonstrating the for loop The value of i is 0 The value of i is 1 The value of i is 2 The value of i is 3 Completed with i=4In a for loop, you must specify three expressions separated by semicolons. The first expression is for initializing a variable to its starting value. The second expression gives a condition which is checked before each iteration of the loop executes; if this expression is true, the loop executes. If it’s false, the loop terminates. The third condition gives an expression which increments the loop counter.
Though most "for" loop expressions just update a counter, you can also use "for" loops for more advanced things like traversing linked lists, by using the appropriate initialization, termination, and increment expressions.
In all of the flow control statements, you can either execute a single statement, without brackets, as follows:
for (i = 0; i < 4; i++) print("The value of i is %d", i);Or you can execute multiple statements, surrounded by brackets, like this:
for (i = 0; i < 4; i++) { print("The value of i is"); print("%d\n", i); }
// Example of "do" loop. void DoExample(void) { int i; print("Demonstrating the do loop"); i = 0; do { print("The value of i is %d\n", i); i = i + 1; } while (i < 4); print("Completed with i=%d\n", i); }The output of this loop is:
Demonstrating the do loop The value of i is 0 The value of i is 1 The value of i is 2 The value of i is 3 Completed with i=4
// Example of "while" loop. void WhileExample(void) { int i = 0; print("Demonstrating the while loop"); while (i < 4) { print( "The value of i is %d\n", i); i = i + 1; } print("Completed with i=%d\n", i); }The output of this loop is:
Demonstrating the do loop The value of i is 0 The value of i is 1 The value of i is 2 The value of i is 3 Completed with i=4
// Example of "while" loop. void WhileExample(void) { int i; print("Demonstrating break"); for (i = 0; i < 10; i++) { if (i == 3) break; print("The value of i is %d\n", i); } print("Completed with i=%d\n", i); }The output of this loop is:
Demonstrating break The value of i is 0 The value of i is 1 The value of i is 2 Completed with i=3
// Example of simple "if". if (LightBrightness < 20) print("My light is dim\n"); // Example of "if-else". if (LightBrightness < 20) print("My light is dim\n"); else print("My light is bright\n");
// Example of switch-case. void TestSwitch(void) { // Executed one of the case statements below, based on // the value in LightType. switch (LightType) { case LT_None: print("There is no lighting\n"); break; case LT_Steady: print("There is steady lighting\n"); break; case LT_Backdrop: print("There is backdrop lighting\n"); break; default: print("There is dynamic\n"); break; } }A "switch" statement consists of one or more "case" statements, and an optional "default" statement. After a switch statement, execution goes to the matching "case" statement if there is one; otherwise execution goes to the "default" statement; otherwise execution continues past the end of the "select" statement.
After you write code following a "case" label, you must use a "break" statement to cause execution to go past the end of the "switch" statement. If you don’t use a "break", execution "falls through" to the next "case" handler.
Operator | Types it applies to | Meaning |
*= | int, float, vector | Multiply and assign |
/= | int, float, vector | Divide and assign |
+= | int, float, vector | Add and assign |
-= | int, float, vector | Subtract and assign |
|| | bool | Logical or |
&& | bool | Logical and |
& | int | Bitwise and |
| | int | Bitwise or |
^ | int | Bitwise exlusive or |
!= | All | Compare for inequality |
== | All | Compare for equality |
< | int, float | Less than |
> | int, float | Greater than |
<= | int, float | Less than or equal to |
>= | int, float | Greater than or equal to |
<< | int | Left shift |
>> | int | Right shift |
+ | int, float | Add |
- | int, float | Subtract |
% | int | Modulo (remainder after division) |
* | int, float, vector | Multiply |
/ | int, float, vector | Divide |
The above table lists the operators in order of precedence (with operators of the same precedence grouped together). When you type in a complex expression like "1*2+3*4", VavoomC automatically groups the operators by precedence. Since multiplication has a higher precedence than addition, the expression is evaluated as "(1*2)+(3*4)".
The "&&" (logical and) and "||" (logical or) operators are short-circuited: if the result of the expression can be determined solely from the first expression (for example, if the first argument of && is false), the second expression is not evaluated.
In addition, VavoomC supports the following unary operators: