
Representation of 3d objects
============================

The 3d world is represented by:

1) Polygons, which constructed from lists of vertices.  All polygons must
be convex (such as triangles, rectangles, etc.)  The few non-convex
polygons which need to be drawn can easily be constructed from convex
polygons.

2) Primitives, which are groups of polygons.  The polygons in a
primitive are drawn in an arbitrary order, so primitives must always be 
convex objects.  Back-face culling is performed on all polygons within a
primitive unless the object is defined as ALWAYS_VISIBLE (see below) so
that only polygons actually facing the viewer are drawn.

3) Objects, which are created from a hierarchical list of primitives.
An object consists of a root primitive and optional child objects.  If
a transformation is applied to the object (rotation, translation,
etc.) then the transformation will apply to the root primitive as well
as any child objects.

All primitives are sorted with respect to each other to make sure
that overlapping polygons are drawn in the correct order.  The algorithm
for sorting the objects should work for any set of non-intersecting
polygons.


Colours
=======

All objects have a "base" colour associated with them, as well as the
brightness of that colour.  When a polygon is being drawn, the actual
colour used to draw it is found by combining the base colour and the
brightness and also multiplying by a "light source" factor.

When a new base colour is defined, 19 shades of brightness for that
colour are allocated (unless specified otherwise).  The brightness of 
the polygon is used to determine which colour to use.

A maximum of 230 colours can be used in total.


Coordinate system
=================

* Positive values of X mean right, negative values mean left.

* Positive values of Y mean down, negative values mean up.

* Positive values of Z mean away from the viewer, negative values mean
towards the viewer.


Definition of 3d object script language
=======================================

[<data>]	     optional data
<data> ...	     one or more occurrences of data

Anything not enclosed in < > means you actually type it.
Strings must be enclosed in "" and must not be longer than
40 characters.
Parameters must be separated by one or more white space characters
(space, tab, newline etc.)
Commands must terminated by a semicolon.
Comments are delimited by either /*  */ or # and newline
e.g. /* This is a comment */
# This is also a comment

A script file is defined as
script:
    [<command> ...]

Everything is case-insensitive.

A command may be one of the following :

colour <colname> <red> <green> <blue> [<shades>];
or
color <colname> <red> <green> <blue> [<shades>];
    colname: string, used to identify colour
    red: float, value of red component from 0.0 to 1.0
    green: float, value of green component from 0.0 to 1.0
    blue: float, value of blue component from 0.0 to 1.0
    shades: integer, number of shades of this colour to allocate
            (must be between 1 and 64).
	    If this is not given then 19 shades will be used.

Sets up a base colour and different shades of brightness for that
colour.


clear_colours
    Frees all colour definitions


points <pointsname> <x> <y> <z> [<x> <y> <z>] ...;
    pointsname: string, used to identify points list
    x: integer, x coordinate of point
    y: integer, y coordinate of point
    z: integer, z coordinate of point

Sets up a list of points for a primitive object.  The same list can be
used for more than one primitive.


surfaces <surfname> <vertices> <coord> ... [<vertices> <coord> ...] ...;
    surfname: string, used to identify surface list
    vertices: integer, number of points in polygon
    coord: integer, point making up polygon (zero means the first point
	   in the point list, one means the second point etc.)

Sets up a list of surfaces (polygons), which will be used to generate
a primitive object when combined with a list of points.  The same surface
list can be used for more than one primitive.

NOTE: when an object is defined, the order of the vertices may be
changed to ensure that back-face culling will operate correctly.  Unless
the object has the ALWAYS_VISIBLE flag set (see below), the order of the
vertices for each polygon must be clockwise.  Any anti-clockwise
surfaces are re-ordered automatically when an object is defined.  This
means that you cannot use the same surface list in two different objects
having different point lists if the order of the vertices is
different for the two objects.  An error message is generated if this
occurs.


object <objname> [<pointsname> <surfname>] [<extra object information>];
    objname: string, used to identify object
    pointsname: string, name of points list to use for object
    surfname: string, name of surface list to use for object

Defines an object, consisting of a primitive object and optional child
objects.  If no point and surface information is given then this will
be an abstract object, meaning that it will not have any primitive
object associated with it, it will only be a container for other
objects.

    extra object information may be:

    colour <colname> <intensity>
    or
    color <colname> <intensity>
	colname: string, name of base colour to use for object
	intensity: float, intensity of colour from 0.0 to 1.0

    child <objname>
	objname: string, name of object which will be a descendent of
		 this object

    scale <x> <y> <z>
	x: float, amount to stretch object by in the x direction
	y: float, amount to stretch object by in the y direction
	z: float, amount to stretch object by in the z direction

    rotate_x <angle>
	angle: float, angle to rotate object by around the x-axis

    rotate_y <angle>
	angle: float, angle to rotate object by around the y-axis

    rotate_z <angle>
	angle: float, angle to rotate object by around the z-axis

    NOTE: all rotations are done wrt the world axis (rather than the
    local axis of the object).

    centre <x> <y> <z>
	x: integer, x coordinate of centre of object
	y: integer, y coordinate of centre of object
	z: integer, z coordinate of centre of object
	The centre is the position of the object relative to the
	centre of the parent object.

    translate <x> <y> <z>
	x: integer, x value of translation
	y: integer, y value of translation
	z: integer, z value of translation
	Moves an instance of an object by the value given relative to its
	current position.

    maxdist <distance>
	distance: integer, maximum distance from viewer for object to
		  still be drawn.

    far_object <objname>
	objname: name of object to be used instead of this one if the
		 object is further away than the maximum distance
		 (that object can also have its own far_object, etc.)
	Note that the position and rotation matrix of <objname> are not
	used when the far_object is drawn.

    detail <objname>
	objname: name of object to be used as surface detail.  Surface detail
	         is drawn immediately after the parent object has been
		 drawn.

    inherit <objname>
	objname: string, name of object from which properties are to
		 be inherited.

    collide
	Specifies that the server should be notified when a player
	collides with this object or one of it's child objects.

    shoot
	Specifies that the server should be notified when a player
	shoots this object or one of it's child objects.

    clear_flags
	Resets all flags (ALWAYS_VISIBLE, etc).  Use if you want to
	inherit from an object which has flags set, but you don't want
	the flags set in the inherited object.

    animate '<commands>'
	Parses <commands> during each frame.  Individual commands should
	be terminated by colons instead of semicolons, e.g:
	animate 'rotate_x 30.0: scale 1.5 1.0 1.0:'
	For rotation, scaling and translation it is not necessary to
	specify the name of the object if the operation is to be
	applied to the current object (as in the above example).
	If more than one "animate" string is given for an object, the
	first animation will be performed during frame 1, the next
	animation string will be performed during frame 2, etc.  To
	perform no animation during a particular frame, include the
	following:
	    animate ':'
	For example:
	    animate 'rotate_x 10.0:'       /* frame 1 */
	    animate ':'		           /* do nothing during frame 2 */
	    animate 'translate -200 0 0:'  /* frame 3 */
	    animate 'translate 200 0 0:'   /* frame 4 */
	    /* then continues at frame 1... */


    portal <worldfile> <x> <y> <z>
	worldfile: string, name of room which a player will be
	transported to if he collides with this object (but not one of
	its child objects).  The server will then send the script file to the
	player to be parsed.
	x: x coordinate of starting position in the world
	y: y coordinate of starting position in the world
	z: z coordinate of starting position in the world

    matrix <a1> <a2> <a3> <b1> <b2> <b3> <c1> <c2> <c3>
	Specifies the 3x3 rotation matrix for the object.
	Equivalent to specifying several separate rotations and scalings.

    <flag>
	flag: any of the object flags such as ALWAYS_VISIBLE (see below).
	      Not enclosed in quotes.


player <playername> <id> <objname> [<options>];
    playername: string, name of player (must be unique)
    id: integer, used to identify player
    objname: string, object used to represent player
    options: shoot or collide options can be specified for the object

This command is used when a moving object (player or projectile) has
been created.  It should not be used inside script files.


create <objname> [<x> <y> <z>];
    objname: string, name of template object to be created
    x: integer, x coordinate of centre of object
    y: integer, y coordinate of centre of object
    z: integer, z coordinate of centre of object

Creates an instance of an object.  The centre of the object can be
specified to override the default positioning of the object (the centre
is relative to the centre of the root world object).


translate <objname> <x> <y> <z>;
    objname: string, name of object to be moved
    x: integer, x value of translation
    y: integer, y value of translation
    z: integer, z value of translation

Moves an instance of an object by the value given relative to its
current position.


position <objname> <x> <y> <z>;
    objname: string, name of object to be moved
    x: integer, x value of centre of object
    y: integer, y value of centre of object
    z: integer, z value of centre of object

Moves an instance of an object to the position given.


scale <objname> <x> <y> <z>;
    objname: string, name of object to be scaled
    x: float, amount to stretch object by in the x direction
    y: float, amount to stretch object by in the y direction
    z: float, amount to stretch object by in the z direction

Scales an instance of an object by the amounts given.


rotate_x <objname> <angle> [local];
    objname: string, name of object to be rotated
    angle: angle of rotation

Rotates an instance of an object about the X axis.
If the "local" keyword is specified then rotations are done wrt to
the object's local axis, otherwise there are done wrt the world axis.


rotate_y <objname> <angle> [local];
    objname: string, name of object to be rotated
    angle: angle of rotation

Rotates an instance of an object about the Y axis.


rotate_z <objname> <angle> [local];
    objname: string, name of object to be rotated
    angle: angle of rotation

Rotates an instance of an object about the Z axis.


max_y <y>;
    y: integer, max y coordinate below which player will die (default: LONG_MAX)


max_fall_height <height>;
    height: integer, max distance player can fall without dying 
            (default: LONG_MAX)


save <objname> <filename>;
    object: string, name of object to be saved
    filename: name of file to save object to

Saves the definition for object <objname> to a file.


background <colname> <intensity>;
    colname: string, name of base colour to use for background
    intensity: float, intensity of colour from 0.0 to 1.0

Changes the background colour of a room.  If no background colour is
set then the background defaults to light blue.


ambient <intensity>;
    intensity: float, intensity of ambient light

Sets the ambient light level.  The brightness of an object usually ranges from
ambient_level*object_intensity to object_intensity (where object_intensity
is the colour intensity set for that object).


light <x> <y> <z> <intensity> [<distance>];
    x: integer, x coordinate of light source
    y: integer, y coordinate of light source
    z: integer, z coordinate of light source
    intensity: float, intensity of light source from 0.0 to 1.0
    distance: float, distance at which light source will be at the
              specified intensity

Adds a light source to the room.  If no light sources are defined for a
room then the viewer is assumed to be the light source.  Multiple light
sources can be defined: if the sum of the intensities of all light sources
equals 1.0 then the brightness of objects will range from the ambient light 
level multiplied by the object intensity up to the intensity set for that 
object.  If the sum of the intensities of the light sources exceeds 1.0
then objects could be lit up brighter than the intensity set for that
object (in the "colour" statement for the object).  If no distance is
specified for the light source then it will have the same intensity no
matter what distance it is from an object.


start <room> <x> <y> <z> [<x> <y> <z> ...];
    room: string, name of room to start in
    x: integer, x value of starting position
    y: integer, y value of starting position
    z: integer, z value of starting position

This command sets up the starting positions for players entering the
game.  The first player to enter the game will start in the first
position given, the second player will start in the second position,
etc.


world <objname> [enclosed];
    objname: string, name of root object for world

This command tells the parser which object to use as the root object
for the whole world.  It should only be used once in the script file.
If "enclosed" is specified, the world is enclosed on all sides and
the screen will not be cleared at the start of each frame (making the
game run faster).


destroy <objname>;
    objname: string, name of an object to destroy

Destroys a previously created object.  If more than one instance of
the object exist then only one of them will be destroyed.  Returns an
error if no instances of the object are found.


remove <objname>;
    objname: string, name of an object to destroy

Same as "destroy" except doesn't return an error if no instances are found.


destroy world;

Destroys the world object (and therefore all instances of all
objects).  It does the same thing as `destroy "<name of world object>";'


destroy all;

Destroys the world object and all moving objects (players and grenades).


Notes
=====

[1] The extra commands in an object definition should not have a semicolon
at the end of each one.  These commands act on the object in the order
they appear, so it is possible, for example, to rotate an object, scale
it, and then rotate it again.

[2] All names must be defined before they are referenced, e.g. the surface
list used in an object must be defined before the object definition
appears.

[3] All angles are in degrees.

[4] Objects defined by "object" commands are templates.  Each template
object can have child template objects, and more than one object can
have the same template object as a descendent.	An object doesn't
actually exist in the world until it has been turned into an
object "instance".  Unlike templates, each instance of an object can
only have one parent, so if more than one object has the same child
object then one instance is created for each.  This means that each
instance of the same object can be transformed independently of the
others.

[5] Instances of objects are created whenever the "world" command is
parsed, and also whenever a new object is put into an existing world
with the "create" or "player" commands.

[6] An object representing a player should be defined so that its centre
is at the top of the player (e.g. the centre of the player's head).
All starting positions for players (as parameters to "portal" and
"start") should specify the starting position on the floor of the
world.	The client program will then move the player up so that
the player is standing with his feet on the floor of the world.

[7] Objects, colours, points, etc. can be redefined as long as the type
of data is not changed (e.g. you can't create a colour "red" and then
create an object called "red").


Object flags
============

NO_COLLISIONS
    If a player comes into contact with the object there will be
    no rebound (i.e. the player can walk through the object).

ALWAYS_VISIBLE
    No back-face culling will be performed for the polygons of the
    object.  Normally only polygons which are facing the viewer are
    drawn but if this flag is set then all polygons are drawn no matter
    which side of the object the viewer is on (used for walls, floors,
    etc.).

INSIDE_OUT
    Only the inside of the object is visible (e.g. a corridor).  This
    flag must be set for objects which the player will be viewing from
    inside, so that back-face culling will operate correctly.

DRAW_FIRST
    Tells the drawing algorithm to always draw this primitive first.
    This flag can be set for the object representing the floor of the
    3d world in order to speed up object sorting.  Should only be used
    for one object.  This flag has no effect when the object is further
    away than its maximum distance (it still won't be drawn).

NO_MATRIX_MULT
    This flag tells the 3d drawing routines that the object will never
    be scaled or rotated.  The object's matrix will be ignored when the
    object is drawn (but if the object's parent has been rotated or scaled
    then that will still affect the child object).  This provides a
    slight speed increase.

NO_SHADING
    None of the object's surfaces will be shaded; they will always
    be drawn at the maximum intensity given for the object.

INSTANT_DEATH
    Player dies if the object is touched.


Note: if an object has a flag set, its children will not automatically
have that flag set.


Collision detection
===================

If the player collides with a polygon which has an elevation of greater than
45 degrees to the horizontal then the player will rebound off it (unless the
height of the polygon is less than 1200 above the player's ground level).
Polygons with an angle of less than 45 degrees can be climbed onto as
long as the height of the polygon is less than 1200 (1.2m) above the
player's ground level, otherwise the player will rebound off the polygon.

This means that players can step onto objects which are less than 1.2m
off the ground.

