                            ====================
                            FTEQCC DOCUMENTATION
                            ====================

Contents by David Walton and Marco Hladik.
Edited and compiled by Marco Hladik.

Last updated: 10th August 2018, 9:21 PM GMT

========
0. INDEX
========

1)  Overview
        1.1) Server-Side QuakeC (SSQC)
        1.2) Client-Side QuakeC (CSQC)
        1.3) Menu QuakeC (MenuQC)
2)  Getting Started
3)  Command-Line
4)  Project Mangement
5)  Other Pre-Processor
6)  Control Statements
7)  Basic Types
        7.1) entity
        7.2) float
        7.3) string
        7.4) int
        7.5) vector
        7.6) __variant
8)  Complex Types
        8.1)  arrays
        8.2)  fields
        8.3)  functions
        8.4)  typedef
        8.5)  enum / enumflags / strongly typed enums
        8.6)  struct
        8.7)  union
        8.8)  class
        8.9)  pointer
        8.10) Accessors
9)  Type Modifiers
        9.1) const / var
        9.2) __unused / noref
        9.3) __used
        9.4) local
        9.5) static / nonstatic
        9.6) nosave
        9.7) inline
        9.8) strip / __ignore
        9.9) shared
        9.10) optional
        9.11) __inout / __in / __out
        9.12) __weak
        9.13) __wrap
        9.14) __accumulate
10) Operators
11) Intrinsics
12) Modelgen Commands
13) Compiler Flags
14) Engine Support

===========
1. Overview
===========

    QuakeC is a language originally created by iD software for use in in the
video game Quake. Vanilla QuakeC is quite a limited language, however with qcc
improvements and engine extensions, its less annoying to write and also much
more capable as a programming language.

Today we're dealing with different types of modules. The original QuakeC only
supported the modification of game-code run on the server. It was not capable
of altering any client-side behaviour. Just send a selection of commands and
hope that the client interprets the stuff properly.


1.1) Server-Side QuakeC (SSQC)
==============================

    This is the classic form of QuakeC, and is the module executed by the server
component. SSQC's reason to exist is so that it can deal with networking. 
It is normally considered authoritive, which is a fancy way of saying that CSQC
isn't to be trusted (if only due to packetloss). 
As such, the SSQC is normally expected to track the state of any entity that has
any impact on the outcome of a game.

In mods designed to run without CSQC, the SSQC generally does a lot more than
just that, however it is also potentially running on a computer on the other
side of the planet, so while you can write your entire game in just the SSQC
module, doing so means that you have no control over the user's actual screen,
and anything that is displayed can be quite laggy which may limit what you can
expect to achieve with SSQC alone.

There are two major variations of SSQC:

[1] NetQuake (NQ):
The original and more common type.

[2] QuakeWorld (QW):
Which was originally meant for deathmatch only. 
It streamlines some things but in the process has a number of omissions that
break singleplayer quake (most qw mods lack any singleplayer/coop logic, with
no support for any monsters).

Thus most engines focus on NQ, even FTEQW!
SSQC tends to be very object orientated. There are comparatively few
non-constant globals as multiple pontential players/etc hinder the use of such
individual globals.


1.2) Client-Side QuakeC (CSQC)
==============================

    This module runs clientside. Each client potentially has its own instance of
CSQC, and thus they'll all end up disagreeing about some part of the game
without the SSQC to provide authoritive information - remember this: 
The SSQC knows best.

CSQC normally has full control over the client's screen (via builtins). It is
normally the CSQC that decides when and where to draw the various hud elements.
The CSQC also has control over the 3d view, and can not only decide where to
draw the 3d view, but it can also change the camera as well as directly control
the entities that are inserted into that view.
However, not every engine supports CSQC, and those that do might have it
disabled for whatever reason.

There are three variations of CSQC:

[1] FTE:
This was the first version of CSQC (if you ignore that CSQC was predated by
menuqc). It is also the one that supports the most extensions since.

[2] DP:
DP's CSQC implementation was an attempt to follow a poorly understood and
incomplete description of FTE's CSQC implementation. As a result, it does
many things in a sub-par way and refuses to improve upon any of it because
doing so might break one of the mods that use it.
Even so, you can still achieve some awesome stuff with it, it just tends to
be more limited than in FTE.

[3] Simple CSQC:
This variation of CSQC is a cut down version of CSQC. It is restricted from
various actions and is unable to query anything about the game beyond the
stats. Its sole purpose is to allow it to draw 2d elements including hud,
scoreboard, and menus. The crc of the csprogs.dat explcitly matches that
of the nq progs.dat, which allows client+server to reuse various builtins
etc, simplifying the implementation further, this also permits the entry
points to be provided by the progs.dat itself although this is more of a
convienience than anything else (it should still run in a seperate VM and
thus have no access to ssqc state).
As an improper subset, it is trivial to create a DP-compatible csprogs that
wraps the Simple CSQC entrypoints, allowing one csprogs to run seamlessly in
FTE+QSS+DP, and hopefully also other engines in the future.

CSQC tends to be more procedural than SSQC.
Generally there is only one player so that info can all be stored in globals
instead of entities (splitscreen may require arrays).


1.3) Menu QuakeC (MenuQC)
=========================

    The mythical MenuQC module is responsible for drawing 2d menus.
It serves many of the CSQC's roles, except that it does not get purged on map
changes and is explicitly designed to remain running even when not connected
to a server.
Becase MenuQC was implemented in DP first combined with FTE's actual attempts
at compatibility, there is only a single standard for MenuQC. However, while
MenuQC is standard, both major supporters have their own extensions, but even
worse is that no two engines have the same names for the same cvar.
Indeed, cvar-hell is why it is generally not recommended for a mod to even try
to support more than one engine. Its much easier to just use the engine's menus
instead.
As such, MenuQC is generally used only for standalone total conversions.

==================
2. Getting Started
==================

    The best way to get started is to find an existing qc-only mod (like
id1qc.zip), extract the qc source files somewhere like c:\quake\mymod\src\*.qc,
shift-right-click the extracted .src file and select open-with and find
fteqccgui.exe.

Then in fteqccgui press F7 to compile, then press F5 to run (you'll be prompted
to locate the exe you want to run as well as you quake directory.
In the engine you can then just load a map.

One common suggestion is to open weapons.qc, find the W_FireRocket function, and
to then change the velocity multiplier for really slow moving rockets, just to
see that you've made a change. There are many many other things you could do
instead, of course. 

Your mod, your choice.

===============
3. Command-Line
===============

    Many commandline arguments are best migrated to pragmas, or set via
fteqccgui's options menu.

[*] -src path
Specifies the directory to start looking in for source files. Mostly redundant.

[*] -srcfile foo.src
Specifies the .src file to start with.

[*] -o output.dat
Explicit output file name.

[*] -O3
Sets optimisations to max. Do not use in addons.

[*] -O2
Sets optimisations to high.

[*] -O0
Turns all optimisations off. You do NOT want this. Optimisations are required in
order to avoid wasting defs.

[*] -std=foo
Reconfigures compiler keywords+flags in order to attempt better compatibility
with the syntax of other QC compilers. There are absolutely no guarentees, nor
should there be much expectations...

[*] -Kfoo / -Kno-foo
Enables the named keyword.
Keywords that are not enabled are still usable with a double-underscore prefix,
so enabling/disabling them is more for compatibility.

[*] -Ffoo / -Fno-foo
Enables disables various compiler flags. There's a number of them, they're not
all useful either, and changing them mid-way through development will generally
result in new bugs in code that was working before. Consult fteqccgui's options
menu for a list.

[*] -Tfoo
Instructs fteqcc to target a specific instruction set and output format.
Common options are: standard, fte, h2, dp, qtest.
You may prefer to use '#pragma target foo' instead.
Using -Th2 also enables some additional keywords in order to act like hcc.
Other targets do not.

[*] -Dvariable[=value]
Defines the named preprocessor macro with the given value.

[*] -Isomepath
Registers an alternative include path, for included files that might otherwise
be considered missing.

[*] -Wall
Enables nearly all warnings.

[*] -Wextra
Enables more warnings than are useful. Many might be unfixable.

[*] -Werror
All warnings will be treated as errors.

[*] -Wno-mundane
Disables a number of warnings that you probably don't care too much about.

[*] -v
Verbose. Can be used multiple times to increase verbosity. Twice will include
autocvar output, which should simplify creation of your mod's default.cfg

[*] --version
Prints out the version of fteqcc and then quits.

[*] -stdout
Runs fteqccgui as if it were fteqcc (ie: compiles and quits without creating any
gui windows). Note that if you want to see the output on windows then you'll
need to pipe the output through some other program.

====================
4. Project Mangement
====================

    All QuakeC starts with a single file - aka the .src. 
This file comes in two forms.

1) Old style:
    First token: treated as equivelent to #output "thetokenhere"
    Other tokens: treated as equivelent to #include "thetokenhere"
    Preprocessor may be used in this file only after the first token.
2) New style:
    First token MUST have a leading #, and is typically #output "filename".
    The rest of the code is treated as a .qc file in its own right, including
    function defs etc.
    Usually the code will be include a series of #includes in order to pull in
    any .qc files you wish to compile.

[*] #merge
#merge "existing.dat" Attempts to imports an existing .dat into the compiler's
state. The imported state will lack any and all type information, so you will
need to re-prototype any variables that you use.
With the use of the __wrap keyword, you can rewrite the imported functions,
otherwise you can add additional symbols into the output.
Do NOT use the same filename for both #merge and #output.

[*] #copyright
Allows you to specify a copyright message. This will be embedded at the start of
the file, and will be displayed in a prompt if anyone tries to use fteqccgui's
decompiler on your mod.
You may wish to include the url of your source repo here.

[*] #include
Pulls in another source file, as if its contents had been embedded in the file
instead of the #include line.

[*] #includelist #endlist
Acts as an #include for each line between the #includelist and #endlist lines.

[*] #pragma includedir "path"
Specifies an alternative path from which to include other files. The path is
relative to the file containing the pragma (if not absolute).

[*] #datafile
Certain modes of operation cause FTEQCC to consider the output .dat files to be
zips (eg with the -Fembedsrc argument).
This argument explicitly includes the specified file within the resulting
.dat/zip.

[*] #pragma sourcefile
This pragma names an additional sourcefile to be compiled at the same time.
Thus if you have a progs.src that contains eg:
    #pragma sourcefile "ssqc.src"
    #pragma sourcefile "CSQC.src"
And then you compile that progs.src, fteqcc[gui] will attempt to compile all
three src files. This is strongly recommended for mods that involve a lot of
debugging of more than one module, and is the only way to get fteqccgui to track
the defs from multiple modules.

[*] #output / #pragma PROGS_DAT
Changes the .dat file that will be written from the current .src file.

[*] #message
Spits out a message to the compilers text output.
Does not otherwise affect anything.

[*] #pragma once
This file will be treated as 0-length if it is included again elsewhere.

[*] #error
Acts as a syntax error with user-defined text.
Useful to verify preprocessor state.

[*] #pragma noref STATE
If STATE is 1, then all following definitions will implicitly use the 'noref'
type modifier, which allows the qcc to silently strip them if they are not
actually referenced nor initialised.
This can be used to silence warnings from *extensions.qc files.

[*] #pragma defaultstatic STATE
Enables/disables the assumption that variables should be static. This can be
override on a per-variable basis with the static or nonstatic modifier.
In programming, it can often pay to 'box' things together, allowing you to
guarentee that only a specific part of your code can interact with something
and thereby reduce the number of outside things that will need to change when
refactoring code later on.
Note that static variables are considered to be invisible to the engine also,
which includes spawn functions and entry points, so use with caution.

[*] #pragma autoproto
If used, this must be used before any variables are defined. This causes fteqcc
to compile your code twice. The first time it will look only at definitions
while skipping over any function bodies allowing them to act as prototypes.
The second time it will compile the functions themselves.
Thus this ensures that any global that is declared later can freely be used in
any expressions or functions. Unfortunately this does not also apply to locals,
but this is usually much less of a concern.

[*] #pragma optimise [no-]foo
Enables or disables various specific optimisations without needing to deal with
commandlines etc, which can ensure other users alwways use the same
optimisation.
Note that if the argument is 'addon' then fteqcc will disable any optimisations
that might break addons/mutators. Otherwise accepts 0-3 as does the commandline.

[*] #pragam keyword enable|disable KEYWORD
Enables or disables parsing of a keyword. This can be used as a lazy wat to
avoid conflicts between eg fteqcc's break keyword and quake's break builtin.
Note that all keywords are still available using a double-underscore prefix,
eg '__break;' will always work. Many keywords default to disabled in order to
avoid common conflicts.

[*] #pragam flag enable|disable NAMEOFFLAG
Enables or disables some compiler flag (aka feature). These can affect how
various expressions are interpreted.
The exact list ought to be documented elsewhere.

[*] #pragam warning enable|disable|error|toggle WARNINGCODE
This controls the behaviour of the specified warning. If the warning is enabled
then it'll print as normal. If it is disabled, then the compiler will merely
mute the warning, everything else will still work the same. If the warning is
set to error, then any time that warning is encountered, the compiler will
consider it to be a soft error (aborting after 10 soft errors) and no output
will be generated.
The vanilla qcc silently accepted certain statements that are fundamentally
unsafe, and which many mods of the era used.
It is strongly recommended to make these into werrors instead, if you can.
Not all errors have a warning code to disable them, but those that do will
print their code every time one is encountered. Don't disable them simply
because you're lazy, as this solves nothing (if nothing else at least use
#warning to remind you to fix any spam later).

======================
5. Other Pre-Processor
======================

[*] #define foo bar
Defines a preprocessor constant/macro. Any time the compiler sees 'foo', it will
replace it with 'bar'.
If you have more than one token, it is strongly recommended to include brackets,
otherwise operator precedence can be confused between the code where the macro
is used and its contents (although this may even be desirable in rare
situations).
Multiple-line macros can be specified by a trailing backslash on the previous
line (there must be no whitespace between the backslash and the linebreak).
It is possible to embed preprocessor directives inside macros by using a
trailing backslash with the preprocessor starting on the next line.
However, this sort of vileness is STRONGLY DISCOURAGED, and will generate
warnings.

[*] #define foo(args) bar
Defines a preprocessor macro. This causes foo to act much like a function, with
any tokens matching an argument being replaced with the contents of that
argument, and otherwise acts as a constant.
Note that side effects (like pre/post increments or assignments) as arguments
can trigger multiple times if the argument is evaluated more than one in the
macro, or not at all if its not used.
Thus such side effects are not recommended.
Additionally, the macro should normally enclose each argument inside a
parenthasis in order to avoid operator precendence issues between caller
and macro.
Macros can contain braces or brackets, including unmatched ones, but this is
generally not recommended except possibly in BEGIN_* and END_* macros.
A single hash inside a macro body will 'stringify' the following token.
A double-hash will 'paste' the preceeding and trailing token together, removing
any whitespace, concatenating the two into a single token (which can be used to
generate names of variables/macros according to a base token.

[*] #append foo bar
Appends bar onto the end of the preprocessor macro.
This can be useful for list-like macros.

[*] #undef foo
Forgets the macro specified.

[*] #if EXPRESSION
The expression only supports numbers.
No variables are allowed, not even if they're defined with const.
The expession may contain && and || operators, and may include a special
'defined(x)' intrinsic that returns true if the name is in fact defined as a
macro (not a variable).

[*] #ifdef MACRONAME
Equivelent to #if defined(MACRONAME)

[*] #ifndef MACRONAME
Equivelent to #if !defined(MACRONAME)

[*] #elif EXPRESSION
Acts like #else #if expression but on a single line and without needing an
additional #endif

[*] #else
Parses the following text only if none of the expression in the preceeding #ifs
were false.

[*] #endif
Terminates a conditional preprocessor block.

=====================
6. Control Statements
=====================

[*] break;
Jumps outside of the current for/while/until/do loop, or switch statement.

[*] continue;
Jumps back to the start of the current loop.

[*] return
    return; // for functions defined as returning void
    return foo; // for functions with an actual return type.
    return = foo; // for __accumulate functions that wish to execute accumulated
                    code instead of skipping it all.
    __exit; // exit as if reaching the end of the function.
This is fantastic for confusing decompilers but otherwise should not be used.
The accumulate version above sets an implicit variable which is automatically
returned once control reaches the end of the function.
The other forms will leave the function there and then.
For compatibility reasons, fteqcc does not strictly enforce return types,
however this is bad practise and you really should fix any related warning
if you want to avoid unintended type punning.

[*] goto foo;
Jumps to another location of the current function. The location must be marked.
    goto foo;
    unreachablecode();
    foo:

[*] { }
Blocks are a convienient way to group multiple statements.
Note that any control statement documented as taking either a block or a
statement does so interchangably (and many programming guides recommend that
blocks ALWAYS be used).
Note that blocks can be used outside of control statements too.
This allows for weird grouping or preprocessor workarounds.

[*] if (condition) statement;
The most simple conditional branch.
If the condition is considered true, then the code will be executed, otherwise
it will be skipped. If the expression is followed by an else satement then that
will be executed if the primary block was not.
Large 'else if' chains can be constructed, but you may find switch statements to
be more readable. 
At this point, we have to ask ourselves what the nature of truth really is.
Not in a philosophical sense, but in a programmery sense.

QuakeC looks for truth in multiple ways, and all control statements use the same
basic form of truth, which depends upon types, but unitialised variables are
always FALSE (except field references, which are typically auto-initialised):

    [*] int
    False when 0, true when anything else.

    [*] float
    False when +0, true when anything else. Note that -0 is normally TRUE, but
    some engines might treat this as false regardless, so don't expect things
    to make sense. There's a compile-flag to treat if(-0) as FALSE, for a small
    performance hit.

    [*] strings
    False when NULL, true when not NULL. Note that empty strings are not the
    same as NULL.

    [*] functions
    Only the null function is false (assignments from __NULL__ or other null
    functions can be used to reset a function reference to null).
    Other functions (including SUB_Null) are considered true.

    [*] vectors
    By default, fteqcc compares all three components against +/-0.
    Other QC compilers will typically test the _x component only.

    [*] fields
    Tests for null... Note that (typically) the modelindex field aliases the
    null field, so would be considered false.

    [*] entities
    The world entity is equivelent to null, and thus false. All other entities
    are considered true.

    [*] pointers
    __NULL__ is false, otherwise true.

    [*] __variant
    Danger... don't do this at home.

    [*] arrays, structs, unions
    These complex types cannot be evaluated for truth. You will need to evaluate
    a specific index or member instead.

HexenC adds an inverted form of if statements:

    if not(condition)
        break;
        
Which is especially useful to test the return value of eg fgets, allowing you to
detect end-of-file conditions without breaking when encountering empty lines -
note that `if(!condition)` tests for empty instead of null, and is thus not
suitable in all cases.

[*] for (initial; condition; increment) statement;
Like in C. The initial terms are executed, then the loop will restart for as
long as the condition evaluates to true. The increment term is executed each
time the loop is restarted (including via continues) but not the initial time.
Multiple initial terms or increments can be achieved via use of the comma
operator, while the condition term must use the && or || operators.
Declarations are permitted inside the initial term, but have scope only within
the loop.

[*] while (condition) statement;

[*] do while

    do {
        statements();
    } while( condition );

[*] __state
This is an alternative way to set .frame, .think, and .nextthink in a single
opcode.
    __state [framenumber, functiontothink];	// quake style, accepts expressions,
                                            however do not use pre-increment
                                            nor post-increment as this is
                                            potentially ambiguous - use
                                            brackets if you need this.
    __state [++ firstframe .. lastframe];	// hexen2 style, MUST use immediates
                                            / frame macros.
For the hexen2-style version, the animation automatically repeats
selecting(wrapping) the frame. The cycle_wrapped global will be set according to
whether the animation wrapped or not (starting from a frame outside of the range
does not count as a wrap).

[*] switch / case / default
    switch (expression) {
    case 0:
        statements;
        break;
    case 1..5: // ranges are inclusive, so this includes 5 but not 5.001
        statements;
        break;
    case 6:	// falls through
    case 7:
        statements;
        break;
    default:	// if none of the above cases matched (like 8 or .3)
        statements;
        break;
    }
Switches allow a slightly cleaner alternative to massive if-else-if-else chains.
The case statements define various possible values, with the following code
being executed.
The 'default' statement defines a fallback location to execute from if none of
the cases matched the expression's value. Note that execution will continue
through any later cases, so be sure to use break statements to prevent undesired
fall-throughts.
Cases may be either a single value, or in the case of a numeric expression they
may be a range of values seperated by a double-dot (eg: case 0..1:foo;break;).
Cases are not required to be constants, but they must not be expressions (which
means fixed array indexes are acceptable, but not dynamic indexes).

[*] __thinktime
    __thinktime ent : delay;
is equivelent to 
    ent.nextthink = time + delay;
When using -Th2 on the commandline, the double-underscores are not required.

[*] __until
    __until(condition) {statements;}
A flipped version of while loops - the loop will repeat until the condition
becomes true. When using -Th2 on the commandline, the double-underscores are not
required.

[*] __loop
    __loop { statements; }
Generally its better to use while(1){} or for(;;){} instead
When using -Th2 on the commandline, the double-underscores are not required.

==============
7. Basic Types
==============

7.1) entity
===========

Quake's objects. Each one has its own copy of each and every field.
Except for the world and players, the only difference between each entity is the
contents of its fields.
Note that collision and pvs state is tracked invisibly, and can be updated by
calling setorigin.

7.2) float
==========

These are standard IEEE single precision floats.
If you are attempting to store bit-values in a float then go no higher than 24
bits, failure to adhere to this can result in the lower bits getting forgotten
due to precision issues.

Float immediates can be specified as decimal (eg: 5.3), or as hex (eg: 0x554336
- note the bit limitation means you should stay with 6 hex digits).
Numbers with no decimal point are normally assumed to be floats, but if you wish
to be explicit then you can simply add a trailing point.

Additionally, character codes can be inserted as immediates using eg 'x' for the
ascii value of the x glyph.

A denormalised float is a very small float with its exponent part set to 0,
which is a special case of floats where the mantissa component has no implied
leading bit set to 1.
These thus have the same representation as an integer with up to 23 bits and can
thus be used to manipulate pointers/ents/strings in various hacky ways (as 
popularised by qccx). 
Not only are such hacks not recommended due to engine incompatibilties, but many
CPUs/binaries are explicitly configured to treat all denormalised floats as 0
for performance reasons and so their use isn't recommended even when not
exploiting an engine's QCVM, and any operation that implicitly requires
denormalised floats will generate warnings (which can be disabled).

7.3) string
===========

String immediates take the form of eg: "Hello World". Implicit concatenation
exists and can be used by simply placing two adjacent immediates.
To avoid issues with codepages and unicode conversions, strings should be kept
as ascii where possible, this can be achieved with string escapes instead of
pasting non-ascii values from an external tool.

    [*] \\
    Represents a single backslash character.

    [*] \"
    Represents a single double-quote character without closing the string.

    [*] \'
    Represents a single apostrophe character.

    [*] \n
    Represents a new-line character.

    [*] \r
    Represents a carrage-return character. This should only be used at the end
    of console prints where you wish for the next line to replace the one you
    just printed, and can be used for progress sprints without flooding the
    console too much.

    [*] \s
    Denotes 'special' text. This is an easy way to write red text without
    needing to resort to non-ascii source.

    [*] \0 through \9
    These represent 'golden' numbers.

    [*] \x##
    Represents a single byte with an explicit 8-bit hex value. If your engine is
    configured to interpret text as utf-8 then this will often result in invalid
    character encoding, if above 127.

    [*] \u#
    Represents a utf-8 encoded character. The # represents multiple hex nibbles.
    In order to avoid confusion with trailing text, you may need to terminate
    the string early and resume it again using string concatenation, but another
    string escape works well too. This should only be used for mods that require
    engines to interpret text as utf-8.

    [*] \(      \=      \)
    These three represent the open/center/close characters that are typically
    used for quake's slider glyphs.

    [*] \<      \-      \>
    These three represent the start/middle/end characters of quake's line
    seperator glyhs.

There are a few other escapes, but I cba to document them as I'd rather people
just used \x instead.

Additionally, FTEQCC supports raw strings.
These are specified as eg: 
	R"delim(Your String Here)delim". 
Any and all text within the two brackets is your string - including any new line
characters exactly as they are in the file.
Any escapes are ignored, and will appear in the resulting string as-is
(you'll see the backslashes in-game).

The two 'delim' words in the example must match each other (but can be 0-length)
and are used as a way to allow close-bracket+double-quote pairs to exist inside
the raw string itself, including nested raw strings (so long as the delimiters
differ).
Note that file paths in quake should normally always use the more portable
forward-slash for path seperators, instead of the microsoft-only backslash
seperator.

Some engines support internationalisation. This is achieved by replacing all
strings defined as e.g. _("foo") according to the contents of a progs.LANG.po
file. 
Mods that use this mechanism will likely also need to enable utf-8 support in
the engine, as well as use a unicode font.

Strings in the QCVM are nominally considered to be indexes from the start of
some string table defined by the progs.dat, however there are many special types
of string that are special or flawed.

    [*] null string
    The null string is the only string considered null. It is always empty.

    [*] immediate string
    This is any string immediate that came from inside the qc.

    [*] permanent string
    These are any string that came from parsing map entities.

    [*] engine string
    These strings point into engine memory, and their contents may change at any
    time even when the string reference doesn't. This is why it can be so hard
    to detect when the player's netname field changes - because the field itself
    doesn't actually change.
    
    [*] zoned/allocated strings
    These strings are ones that were returned by the strzone builtin (part of
    the FRIK_FILE extension). These are the ONLY strings that can be safely
    strunzoned in all engines (some engines may silently ignore the null string
    for convienience).
    If your mod mixes permanent strings (or even immediate strings) with
    allocated strings then you may find yourself with no way to decide whether
    you need to call strunzone or not. It is recommended to just strzone in your
    spawn functions etc, despite how ugly that is.
    Note that allocated strings CANNOT safely be stored in globals in certain
    engines, at least not if saved games are to load correctly without strunzone
    crashing on the non-zoned strings loaded from the saved game.
    
    [*] temporary string
    Temp strings are messy and temporary by their very nature.
    Their behaviour is highly engine-specific. Many engines rotate between 16
    engine strings (or 1, in the case of vanilla quake), so after the 16th call
    that returns a tempstring the older tempstrings get overwritten (you can
    renew the string with strcat, but this is somewhat messy). Do not store them
    inside globals or fields. Even temporarily storing a tempstring into a
    global/field can result in warning messages when saving a game.

    QS behaviour: Cycles between 16 tempstrings.
    DP behaviour: Allocates more memory for tempstrings as needed. 
                Fails if strunzone is called on loaded saved games, spams if
                tempstrings are still referenced when saving.
    FTEQW behaviour: Does not distinguish between permanent strings, allocated
                    strings, nor temporary strings. All three have the exact
                    same behaviour - strzone is an alias for strcat (and
                    strunzone is a no-op), and tempstrings are collected only
                    once they are no longer referenced.
                    This avoids most savedgame issues.
    
    
    
    
7.4) int / integer
==================

Generally requires opcode extensions.
Note that unlike C, QC assumes numeric immediates to be floats.
Normally you should use a postfix of i to explicitly make it an int immediate,
but you can also enable a specific compiler flag to assume immediates as ints.

7.5) vector
===========

Vector immediates traditionally take the form of 'x y z', but using [x, y, z] 
allows formulas and thus simpler argument passing.
Note that vector*vector yields a dot-product, while all other operations are
per-channel.
Normally vectors act a bit like unions and define both 'vec' and 'vec_[x|y|z]'
variables allowing for direct channel access, however the _x etc versions are
not always available (eg in arrays). The modern way to access individual
channels is with eg vec.x instead. Note that array indexing also works, so
vec[0] returns the _x component.
Dynamic indexes work also, but with the same performance hit as arrays so it is
generally best to avoid that if you can.

7.6) __variant
===============

This type represents an undefined type no larger than a vector, and should
normally be used only for function arguments or return value, but can also be
used for type punning.

================
8. Complex Types
================

8.1) arrays
===========

FTEQCC supports single-dimension arrays.
float foo[] = {1,2,3,4};
will thus define a float array and will infer its length as 4.
If you need to use an explicit length, or you do not wish to initialise the
array, then you must put the needed length inside the square brackets.
Note that arrays are 0-based, so an array defined as float foo[2]; can be
accessed as foo[0] or foo[1], but any other value (including foo[2]) is out of
bounds. Indexes will be rounded down.
foo.length can be read if you wish to know how long an array is (especially if
the length was inferred for some reason)
Dynamic indexes ARE supported in all cases, however they may come at a
significant performance loss if you do not have extended opcodes enabled, so it
is generally preferable to unroll small loops such that constant indexes can be
used.
Dynamic lengths are not supported at this time.
Arrays are also supported within structs, allowing for (clumsy)
multi-dimensional arrays.

8.2) fields
===========

Fields are defined by prefixing the field's type with a dot.
Every single entity will then have its own instance of the data, accessed via
    eg: self.myfield
Fields are assumed to be constants, with any uninitialsed fields reserving space
in every single entity in order to hold the data. Fields defined as var or
initialised to the value of another field will NOT consume any space within
each entity.

    .float foo; // const, allocates storage.
    var .float bar = foo;
    void() fnar =
    {
        self.foo = 42;
        if (self.bar != 42)
            dprintf("the impossible happened\n");
    };

Note that field references are variables in their own right.
They can be defined as arrays, they can be passed to functions etc (eg the find
builtin depends upon it).
A word of warning though - field references will not appear in most saved game
formats. That's probably fine for deathmatch, but if you're using them for
singleplayer then be sure to initialise them (even if to the value of another).

8.3) functions
==============

In QuakeC, functions are both a function reference/variable, and typically a
function immediate/body, much like a string is both a string reference, and the
string data itself.
So function definitions are initialised in basically the same way as any other
variable, where the function-type syntax is basically just returntype(arglist),
eg:
    returntype(arglist) name = functionbody;
functionbody can then be either some other function, or a function immediate.
As a special exception for C compatibility, the arglist parenthasis can follow
the function's name instead, and when the initialiser is an immediate, the
equals and trailing semi-colon tokens are optional.
Note that function immediates are what contain the bulk of code, and can only be
present within the context of a function type - meaning either in a function
initialisation or via a cast (creating an annonymous function - note that these
are not safe for saved games, so try to avoid their use in ssqc).
Because functions are really function references, you can define them as var, 
and by doing so you can remap/wrap them at any point you wish. function types
can also be used freely within function arguments or anywhere else.
    
    void() somename = {}; // QC-style function
    
    void somename(void) {} // C-style
    
    void() foo = [$newframe, nextfunc] {}; // QC state function ( function
                                        // contains: self.frame = $newframe; 
                                        // self.think = nextfunc; 
                                        // self.nextthink = time+0.1; )
    
    var void() dynreference; // uninitialised function reference, for
                            // dynamically switching functions.
    
    var void() dynreference = somename; // initialised function references work
    
    void(vector foo, float bar) func = {}; // function with two arguments.
    
    void(float foo = 4) func = {}; // function that will be passed 4 for the
                                // first argument if it is omitted.
    void(... foo) func = {
        for(float f = 0; f < foo; f++) 
            bprint(va_arg(f, string));
        }; // variable-args function that passes each arg to another.
        
    void(optional float foo, ...) func = #0; // name-linked builtin where the
                                            // first arg may be ommitted but
                                            // must otherwise be a float, with
                                            // up to 7 other args.
                                            
    void(void) func = #0:foo; // unnumbered-but-named builtin.
    
    void(float foo) func : 0; // hexenc builtin syntax
    
Note that QC can only tell how many arguments were passed using the
variable-argument argcount form. Any optional arguments that were omitted will
have undefined values. Any argumentsspecified after an optional argument must be
omitted if the prior arg is omitted but otherwise must be specified unless they
are optional themselves, or preinitialised.
Preinitialised non-optional arguments can be omitted, their preinitialised value
will be passed in this case. If the argument list is empty (ie: two adjacent
commas in the call), then the argument's default value will be passed
automatically regardless of whether the argument is considered optional.
Builtins can only accept up to 8 args. Non-builtins have a much higher limit.
Vectors count as 1 argument (and thus allow you to pack additional information).

Structs can be passed but will be counted as
ceil(sizeof(thestruct)/sizeof(vector)) arguments.
Named builtins can be used by some (but not all) engines to avoid numbering
conflicts. Typically these builtins must also be numbered as 0.

8.4) typedef
============

    typedef type newname;
    
Typedefs allow the creation of an alias for types.

8.5) enum / enumflags / strongly typed enums
============================================

    enum int
    {
        FIRST,
        SECOND,
        THIRD,
        NINTH=8
    };
    
Provides an easy way to define a set of constants.
enum: Each name will default to one higher than the previous name, with the
first defaulting to 0. enumflags: Each name will default to twice the previous
name, with the first defaulting to 1, ideal for bit flags.

Strongly typed enums are also supported:

    enum class foo { cake, pie, sauce };
    enum class bar { banana, sauce, pie };
    
Standard enums do not have their own scope. So you could not reuse the names of
inside constants.

8.6) struct
===========

Allows you to define a struct, which is useful for boxing multiple related
variables.

    typedef struct
    {
        vector rgb;
        float a;
    } rgba_t;
    rgba_t opaque_red = {'1 0 0', 1};

    void(rgba_t c) fillscreen =
    {
        drawfill([0,0], screensize, c.rgb, c.a, 0};
    };
    void() drawstuff = 
    {
        fillscreen(opaque_red);
    };
These are especially useful when combined with pointers, but can also simplify
copies.

8.7) union
==========

Equivelent to structs, except all struct members start at the same offset.
This can be used for either type punning or compressing mutually-exclusive
fields inside complex struct layouts. By nesting structs, unions and arrays,
you can get some quite complex data structures.
Note that unions and structs define within unions or structs do not need to be
named. Members from child structs will automatically be accessed as if they were
part of the containing stuct.
    struct
    {
        float type;
        union
        {
            struct
            {
                float f;
                vector bar;
            };
            struct
            {
                string s[2];
            };
        };
    } foo[8];
    float() foobar =
    {
        if (foo[4].type)
            return stof(foo[4].s[1]);
        else
            return foo[4].f;
    };

8.8) class
==========

    class foo : entity
    {
        float interval;
        virtual void() think =
        {
            centerprint(enemy, this.message);
            nextthink = time+interval;
        };
        nonvirtual void(enemy e) setEnemy =
        {
            enemy = e;
        };
        void() foo =
        {
        nextthink = time+interval;
        };
    };
    void() someiplayerfunction =
    {
        foo myfoo = spawn(foo, message:"Hello World", interval:5);
        myfoo.setEnemy(self);
    };
    
The above is a terrible example, sorry.
If the parent class is omitted, entity will be assumed.
Class constructors double up as spawn functions, and the spawn intrisic works
in the same way - the named members will be set before the constructor is
called, instead of passing arguments to the constructor (which avoids the need
for overloads etc). The 'interval' field above is defined as a class field.
Such class fields are valid ONLY on entities of that class, which allows for
more efficient memory usage.
Member functions can be defined as virtual (such functions are technically
pre-initialised fields, and thus compatible with things like think or touch),
non-virtual (read: non-inherited), or static (where 'this' cannot be used).

Public, private, protected are parsed like in C++, but ignored.
Only a single parent type can be inherited, and it must be a class or the
general entity type.

8.9) pointer
============

(Note: not a keyword)
As in C, pointers are defined using an asterisk prefix on the type's name.
    float *ptr;			// define a pointer-to-float
    ptr = &self.frame;	// obtain the address of a variable
    *ptr = *ptr + 1;	// access through the pointer (aka: dereference)
In order to define a field that contains a pointer (instead of a pointer to
a fieldref), use '.*float ptr;', or you can define the field using a typedefed
pointer.
Pointers can be used without qcc extensions, however you can only get the
address of an entity's field, and you can only write. This is still sufficient
to rewrite world's fields, but not particuarly useful otherwise.
It is not possible to pass the address of a local into a child function, due to
QCVM limitations. As a work around, you can define the local as static or use
the alloca intrinsic. Generally you should use __[in]out arguments instead.
Classes can be prototyped with just 'class foo;', but any class-specific fields
will not be usable until the actual class definition, which can mean that
methods must have their code defined outside of the class itself.
A method can include only its prototype within the class, and with the eventual
method being defined as eg: 'void() classname::methodname = {};'.

8.10) Accessors
===============

accessors are a weird and whacky way to invoke functions in a more friendly way.
They allow a reference/handle to provide a number of properties that invoke get
or set functions when used. Many of these functions are excelent candidates for
inlining...
A good example is that of setting up a string-buffer type that invokes an
engine's bufstr_get/set builtins, allowing you to write stringbuffer code as if
it were simply accessing an array.
index types can be any type of variable, so eg hash tables can be accessed as:
    hashaccessor["foo"]

Here's an example using the string buffers extension:

    accessor strbuf : float
    {
        inline get float asfloat[float idx] = {
                return stof(bufstr_get(this, idx));
            };
        inline set float asfloat[float idx] = {
                bufstr_set(this, idx, ftos(value));
            };
        
        // we can get away with directly referencing existing functions/builtins
        get string[float] = bufstr_get;
        set string[float] = bufstr_set;
        get float length = buf_getsize;
    };
    void() accessorexample =
    {
        // buf_create normally returns a handle in a float
        strbuf b = (strbuf)buf_create(); 
        
        // We can now use b as if it were defined as string b[];
        // There isn't even a limit to the indexes!
        b[0] = "This is";
        b[1] = "a test";
        b[2] = "of stringbuffer access";
        // gap!
        b.asfloat[4] = 4;
        
        // loop through them all. Note how the length property invokes
        // buf_getsize which tells us the maximum valid index.
        for (float i = 0; i < b.length; i++)
            print(sprintf("%d: %s\n", i, b[i]));
        
        // still needs to be freed though
        buf_destroy((float)b);
    };

An accessor property defined with an & after the access type specifies that the
'this' inside the code can actually be written to. Otherwise it should be
considered const, which is fine in the above case where it is just a handle.
In set properties, the value to assign is simply called 'value'. If there is
just a type with no name inside the array, then the used key will be named
'index'.
The index type can be anything, so long as it is typedefed.
Note that eg 'b.foo' is equivelent to 'b["foo"]' when b is a variable of type
accessor and 'foo' is not a property of b, b has an unnamed property with an
index type of string, and 'foo' isn't an immediate.
This is useful with accessors built around hashtables.
The unnamed property can be a non-array too - such properties can be accessed
only via eg '*b'.

=================
9. Type Modifiers
=================

9.1) const / var
================

Definitions are either constants or variables.
Initialised globals are normally considered constants, while locals are always
assumed to be variables (this part differs from vanilla qcc).
Uninitialised field and function globals are considered const also (const fields
will be auto-initialised, while functions will generate an error if they are not
explicitly initialised).

9.2) __unused / noref
=====================

This variable is probably unused. Don't warn about it.
These variables may also be stripped completely if they are not referenced
anywhere.

9.3) __used
===========

This variable is actually used somewhere, even if the qcc cannot tell that
(eg: by the engine). There will be no warnings about it being unused, and it
will NOT be auto-stripped.

9.4) local
==========

Obsolete prefix that means nothing on its own.
Vanilla QC used this to tell the compiler to expect a variable definition inside
a function (instead of actual code). However, in FTEQCC this should not normally
be needed except with certain rare type modifiers.

9.5) static / nonstatic
=======================

Static globals are visible only within the .qc file in which they are defined.
Static locals are visible only within the function in which they are defined
(but also become persistent and do not lose their values between calls - like
globals).
Note that static variables use name mangling that might get renamed between
releases, which can break saved games if you're not careful.

9.6) nosave
===========

Globals marked as nosave will not appear in saved games.
They will thus lose their values in saved games, which might either be
undesirable, or a clumsy way to detect reloads.
When the game is reloaded, they will typically revert to the values that were
set at time=0.2 on account of the weird way that saved games work.
nosave is recommended for variables that track objects which cannot be reloaded,
like file handles.

9.7) inline
===========

Functions marked as inline will be eligable for inlining for a small performance
boost.
FTEQCC's inlining is limited, and should generally only be used for small
functions (eg ones that exist to just call other functions with a different
argument order etc).

9.8) strip / __ignore
=====================

This variable / function / field is NOT used. Function bodies will be ignored,
and any definitions will be stripped. If the qcc detects that it is still
required somewhere, you will get a compile error. This can be used inside
#defines to create CSQC-only or ssqc-only functions without needing #ifdefs
inside every single function.

9.9) shared
===========

Globals marked as shared will have the same value regardless of which dat it
was defined in within a single QCVM (read: for mutators, not CSQC).

9.10) optional
==============

optional function arguments may be omitted without warnings/errors. Note that
only the engine can tell how many args were actually passed, so this should
normally only be used on builtins.
QC functions should normally use initialised arguments instead. These have
well-defined values if the argument is ommitted (slightly slower, but avoids the
need for extra signalling).

9.11) __inout / __in / __out
============================

Valid only for function arguments.
By default, all function arguments are __in arguments. However, if they're
defined as __inout or __out then any changes the callee made to the argument
will be written back to the passed value in the caller.
__out arguments cannot accept constants, nor any other expression that cannot be
assigned to (like additions etc).
This mechanism allows a function to return multiple values without needing to
resort to vectors nor structs nor pointers.

9.12) __weak
============

Weak symbols will not conflict with other definitions of the same variable.
Weak symbols will be ignored if they are already defined, and replaced if
followed by a non-weak definition with the same name.

9.13) __wrap
============

Defines a function that is a wrapper for a prior instance of the function with
the same name.
There MUST be a function already defined with the same name, you can define one
as __weak if there is not. If you combine __weak and _wrap on the same function,
then the function will be silently ignored if there was no prior define.
Wrappers MUST reference their 'prior' function, but they can do so by discarding
it, eg: (void)prior;

9.14) __accumulate
==================

Accumultate is a more efficient but limited way of combining functions.
Additional definitions of the function will be concatenated onto the end of the
prior function. A followed return statement in any of the prior functions will
prevent any later accumulations from executing - thus an alternative way to
specify return values is recommended, eg: return = 5;

=============
10. Operators
=============

Operator precedence follows somewhat complex rules that do NOT match C's
operator precedence.
As a general rule, QC is more forgiving, at least if you don't expect C
precedence, particuarly around the & and | operators.

Operators are listed in rough order of priority.
Unary operators are normally written with the operator before their argument,
the exception being post-increment/decrement.

[*] . field
The field operator is context sensitive.
If the lhs is an entity then the rhs MUST be a field reference.
If the lhs is a class or struct then the rhs is expected to be a member of that
class or struct (or from a parent class).

If the lhs is a pointer then it will be dereferenced first.
(For compatiblity with C, this operator can be written as -> instead.)

[*] unary ++ and --
These operators come in two forms - pre and post.
For instance, '++foo' preincrements foo, while 'foo--' postdecrements it.
These change the value by 1, either up or down.
The pre form changes the value before reading its value as part of the
expression.
The post form changes the value AFTER it has been used in the containing
expression, and may have additional costs in certain situations.

[*] unary (TYPE) cast
Casts can be used to convert a variable or expression to a different basic type.
Most casts are performed implicitly on assignments (like int->float or vice
versa), but it can often help to be able to cast directly so that you don't
need to assign it to something first.
Some of the explicit-only casts are potentially unsafe. For instance, all
reference or pointer types can be cast to integers and back.
This is fundamentally unreliable, but it is available if you think you know what
you're doing. So as a general rule, if you need casts then you're writing code
that needs to be tested properly.
One likely use of casts is for converting classes from a parent type to a child.
The reverse is safe and performed explicitly, but parent to child has no
guanrentee that the class actually is the child type, without explicit checks in
your code. The need for an explicit cast helps remind you that you need to
verify the classname or equivelent.

    childtype foo = (childtype)parentref;

Note that casting floats to ints provides a convienient way to truncate a float
towards 0, eg:

    float f = (int)5.3;

[*] unary ~ bitwise not
Sets any bit that was clear, and clears any bit that was set.
Note that this exploits Two's complement numbers, and thus will usually result
in negative numbers. This does not mean that you should try using more than 23
bits in float-based bitfields, but should be safe so long as the upper 9 bits
are sign-extended.

[*] unary * dereference
Dereferencing a pointer means to follow the pointer back to the piece of memory
that the pointer refers to, either to read or write that memory.
It is possible to write to pointers without opcode extensions, but not read from
them.

[*] unary & reference
Obtains the address (aka: a reference) to the specified value.
This cannot be used on intermediate values, but can be used on array lookups,
fields, or globals.
This operator normally REQUIRES opcode extensions, however &self.skin is valid
even without, but the resulting pointer should be considered write-only.

[*] * multiply
Vector * vector is actually a dotproduct.
That is: (lhs_x*rhs_x)+(lhs_y*rhs_y)+(lhs_z+rhs_z)] and thus results in a single
float instead of a vector type.
Otherwise vectors and floats can be mixed, with the vector scaled by the float.

[*] / divide
Divides the left hand side by the right.
Vectors are only supported as the lhs. The rhs must always be a float or int.
If both arguments are ints then the result will round towards 0.

[*] % modulo
Performs a division, but returns the remainder (which might be 0).
This is true even for floats where none of the lhs, rhs, nor the result are
required to be a whole number.

[*] & bitwise and
The return value is the set of bits that are set in both the lhs and rhs.
Vectors can be used (but not mixed).

[*] | bitwise or
The return value is the set of bits that are set in either the lhs and rhs.
Vectors can be used (but not mixed). Note that due to floating point precision,
floats (or vector components) are limited to about 23 bits. Trying to set more
bits will result in a loss of precision which will typically result in the
lowest bits being forgotten.

[*] ^ - bitwise xor
The return value is the set of bits that are set in one one of the lhs and rhs,
with any bits set in both or neither being clear.
This is useful for toggling individual bits.

[*] << left shift
Shifts the number to the left. This is better understood in binary.
The lhs is multiplied by 2 several times (as described by the rhs).
If the rhs is 0 then the result is simply the lhs. Behaviour is undefined if rhs
is not a whole number, or is negative.
Cannot be performed on vectors.

[*] >> right shift
Shifts the number to the right. This is better understood in binary.
The lhs is divided by 2 several times (as described by the rhs).
If the rhs is 0 then the result is simply the lhs. Behaviour is undefined if rhs
is not a whole number, or is negative.
Cannot be performed on vectors.

[*] >< crossproduct
Only works on vectors. Returns the crossproduct of the two vectors, which is an
vector that is tangenital to both input vectors. The length of the result is
scaled by the length of the two inputs. The direction of the resulting vector
can be flipped by swapping the lhs and rhs values (or just negating the result).

[*] + add
Adds the two arguments together.
Mixing vectors and floats is not supported.

[*] - subtract
Subtracts the rhs from the lhs.
Mixing vectors and floats is not supported.

[*] == and !=
This compares two variables looking for equality. This is not a simple compare,
and thus null strings will be considered equal to merely empty strings. +0.0 and
-0.0 will compare as equal, etc.
== results in 1 when they are equal. != results in 1 when they are not equal.
Otherwise both result in 0.

[*] >= <= < >
Numeric comparisons. Valid for floats, ints and pointers, but not vectors, ents,
fields, functions, etc

[*] unary ! logical not
Evaluates the truth of its argument, and flips it, resulting in either 1.0 or
+0.0. Empty strings are considered false, vectors are considered in their
entirety, floats consider -0.0 to be false, otherwise tests for null.

[*] = assignment
This is the standard assignment operator. This operator accepts any type
(including structs/unions) except arrays, but the rhs MUST be compatible with
the lhs type. Assignments and initialisers work a little differently, with
initialisers having implicit types and thus allowing function bodies or structs
to be defined without casts.

[*] += -= |= &= &~= ^= *= <<= >>= /=
These are special assignment operators that perform an operation on the target.
For example, 'lhs += rhs' is equivelent to 'lhs = lhs + rhs;'.
This applies to each operator listed.
Thus foo *= 4; will multiply foo by 4, and store the result into foo, basically
'lhs OP= rhs;' is equivelent to 'lhs=lhs OP rhs;'
(note that &~= is equivelent to TWO operators, specifically
'lhs = (lhs) & ~(rhs);', but otherwise follows the same form)

[*] (+) bitset
Equivelent to 'lhs |= rhs;' or 'lhs = lhs | rhs;', changing lhs to a value which
includes all bits that were set in the rhs.
This operator is implemented for hexenc compatibility.

[*] (-) bitclear
Equivelent to 'lhs = lhs & ~rhs;', changing lhs to a value which has no bits
set that were in the rhs.
This operator is implemented for hexenc compatibility.

[*] ternary ?: conditional
Given the line 'result = A?B:C;', the result will be be equal to B ONLY if A is
true, otherwise equal to C. B may be ommitted, and if so will be equivelent to
A. Side effects will not be executed in the side that was not taken.

[*] && logical and
Asesses the truth of the lhs and rhs sides, and results in 1.0f if BOTH sides
are considered true, and 0.0f if neither or only one is considered true.
Does NOT early-out - both sides WILL be executed in full. (There is a
compiler-flag to enable early-out, in which case the lhs will always be
executed, but the rhs will be skipped if the lhs is true.)
Truth is a matter of who asks, and this comparison always considers -0.0 to be
false.

[*] || logical or
Asesses the truth of the lhs and rhs sides, and results in 1.0f if EITHER side
is considered true, and 0.0f if neither is considered true.
Does NOT early-out - both sides WILL be executed in full. (There is a
compiler-flag to enable early-out, in which case the lhs will always be
executed, but the rhs will be skipped if the lhs is false.)
Truth is a matter of who asks, and this comparison always considers -0.0 to be
false.

[*] , list
Seperates a list of expressions.
The following does not apply to argument lists - function call parsing uses
EVERY argument.
The return value of 'a,b' is actually just the rhs, but any side effects in the
lhs will be executed first. This inclues assignments or pre/post-increment
operators.
Thus lists are useful only where you want hidden sideeffects.

    vector tmp; vec = ( tmp_x = 5, tmp_y = 4,tmp_z = 7, tmp );

Is equivelent to 'vec = [5,4,7];' and thus has limited use in macros or to
express multiple statements without the use of a block and any extra indentation
required by coding style guides.

==============
11. Intrinsics
==============

[*] _(string strimmediate)
Defines a translation string. This auto-generates a symbol prefixed with 
'dotranslate_'. Certain engines can then use this to automatically replace your
strings with strings containing text from other natural languages, via the use
of a .po file (eg: progs.en_gb.po). You can use some part of the gnu gettext
library to extract these.
This intrinsic can be used even at global scope for initialisers.

[*] sizeof(variableortype)
This function accepts either variables or types, and reports the size-in-bytes
of the variable (or a variable of that type). When used on arrays, it returns
the size of the entire array (dereference it to read the size of a single
element of the array), but usually you should just read thearray.length instead.

[*] alloca(bytes)
Attempts to allocate stack memory, and returns a pointer.
This memory will be released when your current function returns.

[*] va_arg(index, type)
When in a QC function defined as accepting variable arguments, this reads the
nth argument, and interprets it as the specified type.
I would generally recommend to avoid variable arguments on qc functions on
account of there being no type checking, as well as performance issues with
emulated arrays.
Ideally, use optional or even __variant args instead.

[*] random([min,] max)
Returns a random number between min and max. If there's only one argument, then
the min argument will be interpretted as 0.
Note that this works by invoking the engine's arg-less random() builtin, and
said builtin MAY return 1 in various engines (but NOT fte+qss+dp) which can and
WILL result in bounds check issues.

[*] randomv([min,] max)
Returns a random vector within the specified box.
Note that different engines handle random() differently, and this can and
eventually WILL result in bounds check issues when combined with arrays.

[*] spawn(classtype, field1:value1, field2:value2, ...)
This uses the regular spawn builtin and then assigns to the fields for that
specified class, then calls the class's constructor before returning the new
object to the caller.
It is worth noting that this is consistent with map entities.

[*] used_sound(soundname) / used_model(modelname)
Arguments MUST be string constants/immediates.
These serve to silence warnings about sounds or models being precached but not
use. This can legitimately happen if there is a setmodel call that accepts
(as fteqcc can only flag constant modelnames, not variables.
They return their arguments, so eg:

    self.mdl = used_model("progs/foo.mdl"); 

..is fine.

[*] autocvar(name, value[, description])
Creates an autocvar with the specified name (not quoted). The autocvar's type
will be inferred from the value's type (which must be an intrinsic).
The description is useful only in combination with the '-v -v -v' argument
tupple, which dumps a list of all autocvars for easy copying into some
default.cfg file (as well as other output).

[*] entnum(ent)
Probably unsafe. Attempts to guess the entity's index.
Ideally use the num_for_edict builtin instead, if you can.

[*] precache_sound 
[*] precache_model
[*] precache_texture
[*] precache_file
[*] setmodel
[*] localsound
[*] sound
These intrinsics affect warnings about redundant/missing precaches.
precache_file lines might get stripped (along with their arguments).
Otherwise they are simply their normal builtins.
If using the outdated write-paks feature, the named files will be included into
paks numbered according to the numeric postfixes used on the precache intrinsic.

[*] floor
[*] ceil
[*] sin
[*] cos
[*] log
[*] sqrt
[*] pow
[*] mod
[*] bitshift
These intrinsics mirror their builtins, falling back to the builtin where the
arguments are not constants.

=====================
12. Modelgen Commands
=====================

    iD software's modelgen and spritegen tools were designed to read special
commands directly from qc files, ensuring that data was kept in sync.

Those tools are basically irrelevant now, but the qc syntax remains regardless,
and has been extended Model generation commands always start on a new line with
a leading $ char.

[*] $cd
[*] $origin
[*] $base
[*] $flags
[*] $scale
[*] $skin
Does nothing.

[*] $frame foo bar etc
Defines a series of frame macros. One per token.
Duplicate names will generate a gap (and a warning).
The compiler will then expand any $foo tokens to a 0-based float that is one
higher than the previous macro.

[*] $modelname
Allows for switching between models easily.
Models are expected to use different frame names.

[*] $framesave NAME
Saves the number of frame macros. Use $framerestore to return to it as needed.

[*] $framerestore NAME
Sets up the next $frame to return to a previous value.

[*] $framevalue IDX
Sets up the next $frame to use the specified value

[*] $flush
Wipes the list of valid frame macros.

==================
13. Compiler Flags
==================

    These are enabled with -Ffoo or disabled with -Fno-foo.
Many (but not all) can also be reconfigured mid-compile, using:
    #pragma flag [en|dis]able foo

[*] -acc
Reacc support.
Reacc is a pascall like compiler. It was released before the Quake source was
released.
This flag has a few effects. It sorts all qc files in the current directory
into alphabetical order to compile them. It also allows Reacc global/field
distinctions, as well as interprets | chars as new-line in strings.
Whilst case insensitivity and lax type checking are supported by reacc, they
are seperate compiler flags in fteqcc.

[*] -qccx
QCCX syntax
WARNING: This syntax makes mods inherantly engine specific.
Do NOT use unless you know what you're doing.
This is provided for compatibility only.
Any entity hacks will be unsupported in FTEQW, DP, and others, resulting in
engine crashes if the code in question is executed.

[*] -kce
Keywords Coexist
If you want keywords to NOT be disabled when they a variable by the same name
is defined, check here.

[*] -parms
Define offset parms
When set, defines explicit PARM0 PARM1 etc symbols (instead of leaving the
unnamed). These are useful if you make use of the asm keyword for function
calls, or you wish to create your own variable arguments. This is an easy way to
break decompilers.

[*] -autoproto
Automatic Prototyping
Causes compilation to take two passes instead of one. The first pass, only the
definitions are read. The second pass actually compiles your code. This means
you never have to remember to prototype functions again.
Note that while you cannot change this flag mid-compile, you can use:
    #pragma autoproto 
..before any symbol declarations, which can help avoid special compilation
instructions for third-parties etc.
This does not work for type declarations - typedefs must still be in logical
order.

[*] -wasm
Dump Assembler
Writes out a qc.asm which contains all your functions but in assembler.
This is a great way to look for bugs in fteqcc, but can also be used to see
exactly what your functions turn into, and thus how to optimise statements
better.
It is generally favourable to use the annotate option instead.

[*] -annotate
Annotate Sourcecode
Annotate source code with assembler statements on compile (requires gui).

[*] -nullemptystr
Null String Immediates
Empty string immediates will have the raw value 0 instead of 1.

[*] -ifstring
if(string) fix
Causes if(string) to behave identically to if(string!="") This is most useful
with addons of course, but also has adverse effects with FRIK_FILE's fgets,
where it becomes impossible to determin the end of the file. In such a case, you
can still use asm {IF string 2;RETURN} to detect eof and leave the function.

[*] -iffloat
if(-0.0) fix
Fixes certain floating point logic. Without this, (-0.0) will be considered true
inside conditionals, while (!-0.0) will ALSO be considered true.

[*] -ifvector
if('0 1 0') fix
Fixes conditional vector logic. Without this, conditionals will consider only
the first component, using the same rules for single floats.

[*] -vectorlogic
v&&v||v fix
Fixes conditional vector logic. Otherwise these operators would check only the
first component.

[*] -brokenarray
array[0] omission
Treat references to arrays as references to the first index of said array, to
replicate an old fteqcc bug instead of returning a pointer to the first element
of the array.

[*] -rootconstructor
root constructor first
When enabled, the root constructor of classes should be called first, just like
in C++.

[*] -caseinsens
Case insensitivity
Causes fteqcc to become case insensitive whilst compiling names. It's generally
not advised to use this as it compiles a little more slowly and provides little
benefit. However, it is required for full reacc support.

[*] -lax
Lax type checks
Disables many errors (generating warnings instead) when function calls or
operations refer to two normally incompatible types. This is required for
reacc support, and can also allow certain (evil) mods to compile that were
originally written for frikqcc.

[*] -hashonly
Hash-only constants
Allows only the use of #constant for precompiler constants, allows certain
preqcc using mods to compile. Specifically, preprocessor macros will NOT be
expanded unless they explicitly have a leading #.

[*] -lo
Logic ops
This changes the behaviour of your code. It generates additional operations to
skip the rhs of && and || expressions where the lhs prevents the rhs from being
significant (like in C). With this flag, the line if (0 && somefunction()) will
never call the function. It can thus be considered an optimisation.
However, due to the change of behaviour, it is not considered so by fteqcc.
Note that due to inprecisions with floats, this flag can cause runaway loop
errors within the player walk and run functions (without iffloat also enabled).
This code is advised:
    In player_stand1:
        if (self.velocity_x || self.velocity_y)
    In player_run: 
        if (!(self.velocity_x || self.velocity_y))

[*] -msvcstyle
MSVC-style errors
Generates warning and error messages in a format that MSVC understands, to
facilitate IDE integration.

[*] -debugmacros
Verbose Macro Expansion
Print out the contents of macros that are expanded.
This can help look inside macros that are expanded and is especially handy if
people are using preprocessor hacks.

[*] -filetimes
Check Filetimes
Recompiles the progs only if the input file modification times are more recent
than that of the output file. Requires old-style .src files and will ignore
modification times of #included files. If nothing changed then the compiler
quits early without writing any output.

[*] -fastarrays
fast arrays where possible
Generates extra instructions inside array handling functions to detect engine
and use extension opcodes only in supporting engines.
Adds a global which is set by the engine if the engine supports the extra
opcodes. Note that this applies to all arrays or none.

[*] -assumeint
Assume Integers
Numerical constants are assumed to be integers, instead of floats.

[*] -subscope
Subscoped Locals
Restrict the scope of locals to the block they are actually defined within, as
in C.

[*] -typeexplicit
Explicit types
All type conversions must be explicit or directly supported by instruction set.

[*] -boundchecks
Disable Bound Checks
Disable array index checks, speeding up array access but can result in your code
misbehaving.

[*] -nofileline
Ignore #pragma file
Ignores #pragma file(foo) and #pragma line(foo), so that errors and symbols
reflect the actual lines, instead of the original source.

[*] -embedsrc
Embed Sources
Write the sourcecode into the output file. The resulting .dat can be opened as a
standard zip archive (or by fteqccgui).
Good for GPL compliance!

==================
14. Engine Support
==================

    Different engines support different extensions.
These take the form of added builtins, new fields with special side effects (or
even existing fields with new values meaning new stuff), or globals that report
additional results or change the behaviour of existing builtins.
Engine extensions can be useful but they can also restrict which engines your
mod can run on. You'll need to find the right compromise for your mod yourself.

Most of the common important extensions can be queried at run time.
This is done eg as following:

    if (cvar("pr_checkextension"))
        if (checkextension("FRIK_FILE"))
            canopenfiles = TRUE;

Note that QuakeC does not normally early-out, so the two if statements must be
nested and not replaced with an && operator.
FTEQW (and QSS) have a few builtins that have no formal named extension.
These can be queried with eg the following:

    if (cvar("pr_checkextension"))
        if (checkextension("FTE_QC_CHECKCOMMAND"))
        {
            if (checkbuiltin(search_getfilemtime))
                cancheckmodificationtimes = TRUE;
            if (checkcommand("cef"))
                canusewebbrowserplugin = TRUE;
        }

Upcoming is a list of the engines with extensive extensions.
These files typically contain comments that describe the new stuff either on a
per-feature basis or per-extension basis.
If you don't understand the description of a feature for one engine then you may
find another engine describes it with greater clarity.

[*] FTE
    http://fte.triptohell.info/moodles/fteqcc/fteextensions.qc
[*] QSS
    http://fte.triptohell.info/moodles/qss/QSS_DevKit.zip
[*] DP
    http://svn.icculus.org/twilight/trunk/darkplaces/dpdefs/

