
------------------------------------------------------------------------------
 Numeric constants
------------------------------------------------------------------------------

Integer:

	256			// Decimal
	0x0fe3		// Hexadecimal
	2_0100101	// Any radix

Floating point:

	20.5, 0.1, .25, 18.

------------------------------------------------------------------------------
 String literals
------------------------------------------------------------------------------

newline (LF)			\n		10
horizontal tab (HT)		\t		9
verticle tab (VT)		\v		11
backspace (BS)			\b		8
carraige return (CR)	\r		13
formfeed (FF)			\f		12
audible alert (BEL)		\a		7
backslash				\\		92
double quote			\"		34
hex number				\xhh	--

Contiguous string literals are concatenated into a single string:

string TestMessage =
	"This is a test.\n"
	"A test of the compiler string concatenation.\n"
	"The quick brown fox jumps over the lazy dog.\n";

------------------------------------------------------------------------------
 Constant definitions
------------------------------------------------------------------------------

constant FALSE = 0;
constant TRUE = 1;
constant OFF, ON;
constant NO, YES;
constant TEST1 = 1, TEST2, TEST3, TEST10 = 10, TEST11;

constant
	T_MONSTER = 0x00f0,
	T_BARREL,
	T_ROCK,
	T_TELEPORT;

------------------------------------------------------------------------------
 External code and data declarations
------------------------------------------------------------------------------

Primaries are callable functions provided by the game engine.

primary -- OpenDoor();
primary -- GetTime() float "time";
primary -- ActivateThing(int, int) float;
primary -- GetGameInfo() int "NumPlayers", int "GameType";

Naturals are data provided by the game engine.

natural int -- PlayerCount;
natural entity -- LevelBoss;
natural float -- StartX, StartY, StartZ;

------------------------------------------------------------------------------
 Service definitions
------------------------------------------------------------------------------

service CrumbleBridge
{
	...
}

service ActivateLadder; // Empty
service ActivateLadder2 {}  // Empty
service ActivateLadder3
{
	...
}

------------------------------------------------------------------------------
 Routine declarations and definitions
------------------------------------------------------------------------------

routine -- LowerBridge(actor, int) float;

routine LowerBridge(actor bridge, int delta) float "newHeight"
{
}

------------------------------------------------------------------------------
 Variable declaration
------------------------------------------------------------------------------

Assignment is allowed in local variable declaration.

routine DoNothing
{
	int a = 10;
	int b = a+6, c = a+b*2+10;
}

Locals can be declared anywhere in a function/service, but...

service foo
{
	int x;

	{
		int x; // redefinition
	}
}

------------------------------------------------------------------------------
 Working with entities
------------------------------------------------------------------------------

Use the 'establish' keyword to name and define the game entity.

A field name can be followed by a colon and another identifier to create an
alias.  The alias can be preceeded by a new type.

establish entity
{
	entity next, prev;
	entity child;

	string name;

	float x:a, y:b, z:c;

	int i_speed : float f_speed;

	int height;
	int armor;
	entity target;
}

Use the dot operator '.' to access fields of an entity.

	if(parent.child.name == "P_CLERIC")
	// 'name' and 'child' must be entity fields

------------------------------------------------------------------------------
 Open and closed calls
------------------------------------------------------------------------------

Primary and routine call statements are closed by default, meaning all
return values left on the stack are popped automatically.  You can leave a
call open by using the open keyword after the argument list.

	SuccedentProperties();			// closed
	SuccedentProperties() open;		// open

Indirect call statements are open by default.  Use the close keyword after
the argument list to manually pop return values.

	$(runCode);						// open
	$(runCode) close;				// pop 1 return value
	$(runCode) close 4;				// pop 4 return values

------------------------------------------------------------------------------
 Assignment statements
------------------------------------------------------------------------------

	=, +=, -=, *=, /=, %=

	entity = FindNearest(x, y);
	x += momentumX;
	x += momentumX, y += momentumY;

	(x, y, z) <- Locate();

	(x (+=), y (+=), z (+=)) <- GetMomentums();

	x = 0, y = 0;

------------------------------------------------------------------------------
 Multiple return values and stack manipulation
------------------------------------------------------------------------------

routine -- SuccedentProperties() float, float, float;

routine SuccedentProperties()
	float "height", float "delay", float "speed"
{
	...
	return height, delay, speed;
}

	Multiple-assignment operator <-

	// Implicit assigment operator (=)
	(height, delay, speed) <- SuccedentProperties();

	// Explicit assignment operator using parentheses
	(height (+=), delay (*=), speed (-=)) <- SuccedentProperties();

	// Popping values using ??
	(height, ??, speed) <- SuccedentProperties();

	SuccedentProperties() open;
	speed = ??;
	delay = ??;
	pop;

------------------------------------------------------------------------------
 Casting
------------------------------------------------------------------------------

	int i;
	float f;

	i = (int)f;
	f = (float)i;

------------------------------------------------------------------------------
 Using the top stack value
------------------------------------------------------------------------------

 Using ?? in an expression will use the top stack value.

	push 10, 7, 5;
	x = ??; // 5
	y = ??; // 7
	z = ??; // 10

 Be careful...

	push 6;
	x = 2+??*3; // is not 20 (2+6*3), but 12 (6+2*3)!

------------------------------------------------------------------------------
 Code pointers and indirect code calling
------------------------------------------------------------------------------

routine -- SeekTarget() int "xDelta", int "yDelta";

	code thinkRoutine;

	// Acquiring a code pointer
	thinkRoutine = <SeekTarget>;

	// Indirect procedure call (open form is implicit)
	$(thinkRoutine);

	// Indirect procedure call with args
	$(x, y, thinkRoutine);

	// Closing an indirect procedure call (pop return values)
	$(thinkRoutine) close 2;

	// Indirect function call
	(newX, newY) <- $(thinkRoutine);

	// Indirect function call with args
	(newX, newY) <- $(x, y, thinkRoutine);

	// Call using top of stack
	push thinkRoutine;
	$();

------------------------------------------------------------------------------
 File inclusion
------------------------------------------------------------------------------

import "mageslay.h";

Ignores multiple imports of the same file.

------------------------------------------------------------------------------
 Notes
------------------------------------------------------------------------------

&& and || do NOT short-circuit

delay is not a function, it is a statement, and so like return, it does not
require parentheses.

------------------------------------------------------------------------------
 Repeat statement
------------------------------------------------------------------------------

	repeat(10)
	{
		// execute this code 10 times
	}
JFM: NOTE - repeat (0) or any negative number will repeat exactly once!
------------------------------------------------------------------------------
 Loop statement
------------------------------------------------------------------------------

	loop
	{
		// execute this code perpetually
	}

------------------------------------------------------------------------------
 Push and pop statements
------------------------------------------------------------------------------

	push i, i*20, 10;
	pop;
	pop 3;

------------------------------------------------------------------------------
 If statement
------------------------------------------------------------------------------

	if(x == 10)
	{
	}
	else if(x == 20)
	{
	}
	else
	{
	}

	if not(x) // better than "if(!x)"
	{
	}

------------------------------------------------------------------------------
 Until
------------------------------------------------------------------------------

	do { } until(x); // better than "while(!x)"

	until(x) { } // better than "while(!x)"

------------------------------------------------------------------------------
 Switch statement
------------------------------------------------------------------------------

RCC case statements use equality operators (== !=), relational operators
(< > <= >=), and the range operator (..).  If no operator is specified, ==
is implied.

Examples:

	case 5:
	case == 5: // same as above
	case != 8:
	case < 0:
	case > MAX_VALUE:
	case <= 1:
	case >= 10:
	case 1..20: // inclusive

Contiguous 'case' statments can be concatenated using the 'or' keyword:

	case 1 or 2 or 3:
	case < 0 or 10..50 or > 100:
	case "Hello" or "Goodbye":

A 'break' is not needed at the end of a 'switch' statement:

	switch(action)
	{
	case AC_SLIDEDOOR or AC_OPENDOOR:
		OpenDoor();
		break;
	default:
		DefaultAction();
	}
