- moved sources to src/, migrated to cmake

Fri, 10 Jan 2014 16:11:49 +0200

author
Teemu Piippo <crimsondusk64@gmail.com>
date
Fri, 10 Jan 2014 16:11:49 +0200
changeset 71
11f23fabf8a6
parent 70
fc257920ac00
child 72
03e4d9db3fd9

- moved sources to src/, migrated to cmake

CMakeLists.txt file | annotate | diff | comparison | revisions
Makefile file | annotate | diff | comparison | revisions
array.h file | annotate | diff | comparison | revisions
botcommands.h file | annotate | diff | comparison | revisions
bots.h file | annotate | diff | comparison | revisions
commands.cxx file | annotate | diff | comparison | revisions
commands.h file | annotate | diff | comparison | revisions
common.h file | annotate | diff | comparison | revisions
databuffer.h file | annotate | diff | comparison | revisions
events.cxx file | annotate | diff | comparison | revisions
events.h file | annotate | diff | comparison | revisions
main.cxx file | annotate | diff | comparison | revisions
objwriter.cxx file | annotate | diff | comparison | revisions
objwriter.h file | annotate | diff | comparison | revisions
parser.cxx file | annotate | diff | comparison | revisions
preprocessor.cxx file | annotate | diff | comparison | revisions
scriptreader.cxx file | annotate | diff | comparison | revisions
scriptreader.h file | annotate | diff | comparison | revisions
src/array.h file | annotate | diff | comparison | revisions
src/botcommands.h file | annotate | diff | comparison | revisions
src/bots.h file | annotate | diff | comparison | revisions
src/commands.cxx file | annotate | diff | comparison | revisions
src/commands.h file | annotate | diff | comparison | revisions
src/common.h file | annotate | diff | comparison | revisions
src/databuffer.h file | annotate | diff | comparison | revisions
src/events.cxx file | annotate | diff | comparison | revisions
src/events.h file | annotate | diff | comparison | revisions
src/main.cxx file | annotate | diff | comparison | revisions
src/objwriter.cxx file | annotate | diff | comparison | revisions
src/objwriter.h file | annotate | diff | comparison | revisions
src/parser.cxx file | annotate | diff | comparison | revisions
src/preprocessor.cxx file | annotate | diff | comparison | revisions
src/scriptreader.cxx file | annotate | diff | comparison | revisions
src/scriptreader.h file | annotate | diff | comparison | revisions
src/str.cxx file | annotate | diff | comparison | revisions
src/str.h file | annotate | diff | comparison | revisions
src/stringtable.cxx file | annotate | diff | comparison | revisions
src/stringtable.h file | annotate | diff | comparison | revisions
src/variables.cxx file | annotate | diff | comparison | revisions
src/variables.h file | annotate | diff | comparison | revisions
str.cxx file | annotate | diff | comparison | revisions
str.h file | annotate | diff | comparison | revisions
stringtable.cxx file | annotate | diff | comparison | revisions
stringtable.h file | annotate | diff | comparison | revisions
variables.cxx file | annotate | diff | comparison | revisions
variables.h file | annotate | diff | comparison | revisions
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/CMakeLists.txt	Fri Jan 10 16:11:49 2014 +0200
@@ -0,0 +1,12 @@
+add_executable (botc
+	src/commands.cxx
+	src/events.cxx
+	src/main.cxx
+	src/objwriter.cxx
+	src/parser.cxx
+	src/preprocessor.cxx
+	src/scriptreader.cxx
+	src/str.cxx
+	src/stringtable.cxx
+	src/variables.cxx
+)
\ No newline at end of file
--- a/Makefile	Wed Jan 02 23:57:46 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,16 +0,0 @@
-all:
-	g++ -Wall -c -o scriptreader.o scriptreader.cxx
-	g++ -Wall -c -o objwriter.o objwriter.cxx
-	g++ -Wall -c -o str.o str.cxx
-	g++ -Wall -c -o main.o main.cxx
-	g++ -Wall -c -o parser.o parser.cxx
-	g++ -Wall -c -o events.o events.cxx
-	g++ -Wall -c -o commands.o commands.cxx
-	g++ -Wall -c -o stringtable.o stringtable.cxx
-	g++ -Wall -c -o variables.o variables.cxx
-	g++ -Wall -c -o preprocessor.o preprocessor.cxx
-	g++ -Wall -o botc scriptreader.o objwriter.o str.o main.o parser.o events.o \
-		commands.o stringtable.o variables.o preprocessor.o
-
-clean:
-	rm -f *.o *~ botc
--- a/array.h	Wed Jan 02 23:57:46 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,190 +0,0 @@
-/*
- *	botc source code
- *	Copyright (C) 2012 Santeri `Dusk` Piippo
- *	All rights reserved.
- *	
- *	Redistribution and use in source and binary forms, with or without
- *	modification, are permitted provided that the following conditions are met:
- *	
- *	1. Redistributions of source code must retain the above copyright notice,
- *	   this list of conditions and the following disclaimer.
- *	2. Redistributions in binary form must reproduce the above copyright notice,
- *	   this list of conditions and the following disclaimer in the documentation
- *	   and/or other materials provided with the distribution.
- *	3. Neither the name of the developer nor the names of its contributors may
- *	   be used to endorse or promote products derived from this software without
- *	   specific prior written permission.
- *	4. Redistributions in any form must be accompanied by information on how to
- *	   obtain complete source code for the software and any accompanying
- *	   software that uses the software. The source code must either be included
- *	   in the distribution or be available for no more than the cost of
- *	   distribution plus a nominal fee, and must be freely redistributable
- *	   under reasonable conditions. For an executable file, complete source
- *	   code means the source code for all modules it contains. It does not
- *	   include source code for modules or files that typically accompany the
- *	   major components of the operating system on which the executable file
- *	   runs.
- *	
- *	THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- *	AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- *	IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- *	ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
- *	LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- *	CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- *	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- *	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- *	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- *	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- *	POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include "common.h"
-
-#define ITERATE_SUBSCRIPTS(link) \
-	for (link = data; link; link = link->next)
-
-#define foreach_counter(NAME) \
-	(int)(reinterpret_cast<int> (foreach_counter##NAME) / sizeof (foreach_counter##NAME))
-#define foreach(T,NAME,ARRAY) \
-	if (ARRAY.size() > 0) for (T NAME = ARRAY[0], *foreach_counter##NAME = 0; \
-		foreach_counter(NAME) < (int)(ARRAY.size()); \
-		NAME = ARRAY[reinterpret_cast<int> (++foreach_counter##NAME) / sizeof (foreach_counter##NAME)])
-
-// Single element of an array
-template <class T> class arrayElement {
-public:
-	T value;
-	arrayElement<T>* next;
-	
-	arrayElement () {
-		next = NULL;
-	}
-};
-
-// Dynamic array
-template <class T> class array {
-public:
-	array () {
-		data = NULL;
-	}
-	
-	array (T* stuff, unsigned int c) {
-		printf ("%d elements\n", c);
-		data = NULL;
-		
-		for (unsigned int i = 0; i < c; i++)
-			push (stuff[c]);
-	}
-	
-	~array () {
-		if (data)
-			deleteElement (data);
-	}
-	
-	void push (T stuff) {
-		arrayElement<T>* e = new arrayElement<T>;
-		e->value = stuff;
-		e->next = NULL;
-		
-		if (!data) {
-			data = e;
-			return;
-		}
-		
-		arrayElement<T>* link;
-		for (link = data; link && link->next; link = link->next);
-		link->next = e;
-	}
-	
-	T pop () {
-		int pos = size() - 1;
-		if (pos == -1)
-			error ("array::pop: tried to pop an array with no elements\n");
-		T res = subscript (pos);
-		remove (pos);
-		return res;
-	}
-	
-	void remove (unsigned int pos) {
-		if (!data)
-			error ("tried to use remove on an array with no elements");
-		
-		if (pos == 0) {
-			// special case for first element
-			arrayElement<T>* first = data;
-			data = data->next;
-			delete first;
-			return;
-		}
-		
-		arrayElement<T>* link = data;
-		unsigned int x = 0;
-		while (link->next) {
-			if (x == pos - 1)
-				break;
-			link = link->next;
-			x++;
-		}
-		if (!link)
-			error ("no such element in array\n");
-		
-		arrayElement<T>* nextlink = link->next->next;
-		delete link->next;
-		link->next = nextlink;
-	}
-	
-	unsigned int size () {
-		unsigned int x = 0;
-		arrayElement<T>* link;
-		ITERATE_SUBSCRIPTS(link)
-			x++;
-		return x;
-	}
-	
-	T& subscript (unsigned int i) {
-		arrayElement<T>* link;
-		unsigned int x = 0;
-		ITERATE_SUBSCRIPTS(link) {
-			if (x == i)
-				return link->value;
-			x++;
-		}
-		
-		error ("array: tried to access subscript %u in an array of %u elements\n", i, x);
-		return data->value;
-	}
-	
-	T* out () {
-		int s = size();
-		T* out = new T[s];
-		unsigned int x = 0;
-		
-		arrayElement<T>* link;
-		ITERATE_SUBSCRIPTS(link) {
-			out[x] = link->value;
-			x++;
-		}
-		
-		return out;
-	}
-	
-	T& operator [] (const unsigned int i) {
-		return subscript (i);
-	}
-	
-	void operator << (const T stuff) {
-		push (stuff);
-	}
-	
-private:
-	void deleteElement (arrayElement<T>* e) {
-		if (e->next)
-			deleteElement (e->next);
-		delete e;
-	}
-	
-	arrayElement<T>* data;
-};
--- a/botcommands.h	Wed Jan 02 23:57:46 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,173 +0,0 @@
-//-----------------------------------------------------------------------------
-//
-// Skulltag Source
-// Copyright (C) 2002 Brad Carney
-// Copyright (C) 2007-2012 Skulltag Development Team
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// 1. Redistributions of source code must retain the above copyright notice,
-//    this list of conditions and the following disclaimer.
-// 2. Redistributions in binary form must reproduce the above copyright notice,
-//    this list of conditions and the following disclaimer in the documentation
-//    and/or other materials provided with the distribution.
-// 3. Neither the name of the Skulltag Development Team nor the names of its
-//    contributors may be used to endorse or promote products derived from this
-//    software without specific prior written permission.
-// 4. Redistributions in any form must be accompanied by information on how to
-//    obtain complete source code for the software and any accompanying
-//    software that uses the software. The source code must either be included
-//    in the distribution or be available for no more than the cost of
-//    distribution plus a nominal fee, and must be freely redistributable
-//    under reasonable conditions. For an executable file, complete source
-//    code means the source code for all modules it contains. It does not
-//    include source code for modules or files that typically accompany the
-//    major components of the operating system on which the executable file
-//    runs.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-// Date created:  5/18/04
-//
-//
-// Filename: botcommands.h
-//
-// Description: Contains bot structures and prototypes
-// [Dusk] Clipped stuff that botc doesn't need.
-//
-//-----------------------------------------------------------------------------
-
-#ifndef __BOTCOMMANDS_H__
-#define __BOTCOMMANDS_H__
-
-#include "bots.h"
-
-//*****************************************************************************
-//  DEFINES
-
-#define	SETENEMY_LASTSEEN		0
-#define	SETENEMY_LASTSHOTBY		1
-
-// Different results for pathing commands.
-#define	PATH_UNREACHABLE			-1
-#define	PATH_INCOMPLETE				0
-#define	PATH_COMPLETE				1
-#define	PATH_REACHEDGOAL			2
-
-// This is the size of the return string for the bot command functions.
-#define	BOTCMD_RETURNSTRING_SIZE	256
-
-//*****************************************************************************
-typedef enum
-{
-	BOTCMD_CHANGESTATE,									// Basic botcmd utility functions.
-	BOTCMD_DELAY,
-	BOTCMD_RAND,
-	BOTCMD_STRINGSAREEQUAL,
-	BOTCMD_LOOKFORPOWERUPS,								// Search functions.
-	BOTCMD_LOOKFORWEAPONS,
-	BOTCMD_LOOKFORAMMO,
-	BOTCMD_LOOKFORBASEHEALTH,
-	BOTCMD_LOOKFORBASEARMOR,
-	BOTCMD_LOOKFORSUPERHEALTH,
-	BOTCMD_LOOKFORSUPERARMOR,				/* 10 */
-	BOTCMD_LOOKFORPLAYERENEMIES,
-	BOTCMD_GETCLOSESTPLAYERENEMY,
-	BOTCMD_MOVELEFT,									// Movement functions.
-	BOTCMD_MOVERIGHT,
-	BOTCMD_MOVEFORWARD,
-	BOTCMD_MOVEBACKWARDS,
-	BOTCMD_STOPMOVEMENT,
-	BOTCMD_STOPFORWARDMOVEMENT,
-	BOTCMD_STOPSIDEWAYSMOVEMENT,
-	BOTCMD_CHECKTERRAIN,					/* 20 */
-	BOTCMD_PATHTOGOAL,									// Pathing functions.
-	BOTCMD_PATHTOLASTKNOWNENEMYPOSITION,
-	BOTCMD_PATHTOLASTHEARDSOUND,
-	BOTCMD_ROAM,
-	BOTCMD_GETPATHINGCOSTTOITEM,
-	BOTCMD_GETDISTANCETOITEM,
-	BOTCMD_GETITEMNAME,
-	BOTCMD_ISITEMVISIBLE,
-	BOTCMD_SETGOAL,
-	BOTCMD_BEGINAIMINGATENEMY,				/* 30 */	// Aiming functions.
-	BOTCMD_STOPAIMINGATENEMY,
-	BOTCMD_TURN,
-	BOTCMD_GETCURRENTANGLE,
-	BOTCMD_SETENEMY,									// Enemy functions.
-	BOTCMD_CLEARENEMY,
-	BOTCMD_ISENEMYALIVE,
-	BOTCMD_ISENEMYVISIBLE,
-	BOTCMD_GETDISTANCETOENEMY,
-	BOTCMD_GETPLAYERDAMAGEDBY,
-	BOTCMD_GETENEMYINVULNERABILITYTICKS,	/* 40 */
-	BOTCMD_FIREWEAPON,									// Weapon functions.
-	BOTCMD_BEGINFIRINGWEAPON,
-	BOTCMD_STOPFIRINGWEAPON,
-	BOTCMD_GETCURRENTWEAPON,
-	BOTCMD_CHANGEWEAPON,
-	BOTCMD_GETWEAPONFROMITEM,
-	BOTCMD_ISWEAPONOWNED,
-	BOTCMD_ISFAVORITEWEAPON,
-	BOTCMD_SAY,											// Chat functions.
-	BOTCMD_SAYFROMFILE,						/* 50 */
-	BOTCMD_SAYFROMCHATFILE,
-	BOTCMD_BEGINCHATTING,
-	BOTCMD_STOPCHATTING,
-	BOTCMD_CHATSECTIONEXISTS,
-	BOTCMD_CHATSECTIONEXISTSINFILE,
-	BOTCMD_GETLASTCHATSTRING,
-	BOTCMD_GETLASTCHATPLAYER,
-	BOTCMD_GETCHATFREQUENCY,
-	BOTCMD_JUMP,										// Jumping functions.
-	BOTCMD_BEGINJUMPING,					/* 60 */
-	BOTCMD_STOPJUMPING,
-	BOTCMD_TAUNT,										// Other action functions.
-	BOTCMD_RESPAWN,
-	BOTCMD_TRYTOJOINGAME,
-	BOTCMD_ISDEAD,										// Information about self functions.
-	BOTCMD_ISSPECTATING,
-	BOTCMD_GETHEALTH,
-	BOTCMD_GETARMOR,
-	BOTCMD_GETBASEHEALTH,
-	BOTCMD_GETBASEARMOR,					/* 70 */
-	BOTCMD_GETBOTSKILL,									// Botskill functions.
-	BOTCMD_GETACCURACY,
-	BOTCMD_GETINTELLECT,
-	BOTCMD_GETANTICIPATION,
-	BOTCMD_GETEVADE,
-	BOTCMD_GETREACTIONTIME,
-	BOTCMD_GETPERCEPTION,
-	BOTCMD_SETSKILLINCREASE,							// Botskill modifying functions functions.
-	BOTCMD_ISSKILLINCREASED,
-	BOTCMD_SETSKILLDECREASE,				/* 80 */
-	BOTCMD_ISSKILLDECREASED,
-	BOTCMD_GETGAMEMODE,									// Other functions.
-	BOTCMD_GETSPREAD,
-	BOTCMD_GETLASTJOINEDPLAYER,
-	BOTCMD_GETPLAYERNAME,
-	BOTCMD_GETRECEIVEDMEDAL,
-	BOTCMD_ACS_EXECUTE,
-	BOTCMD_GETFAVORITEWEAPON,
-	BOTCMD_SAYFROMLUMP,
-	BOTCMD_SAYFROMCHATLUMP,					/* 90 */
-	BOTCMD_CHATSECTIONEXISTSINLUMP,
-	BOTCMD_CHATSECTIONEXISTSINCHATLUMP,
-
-	NUM_BOTCMDS
-
-} BOTCMD_e;
-
-#endif	// __BOTCOMMANDS_H__
\ No newline at end of file
--- a/bots.h	Wed Jan 02 23:57:46 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,272 +0,0 @@
-//-----------------------------------------------------------------------------
-//
-// Skulltag Source
-// Copyright (C) 2002 Brad Carney
-// Copyright (C) 2007-2012 Skulltag Development Team
-// All rights reserved.
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// 1. Redistributions of source code must retain the above copyright notice,
-//    this list of conditions and the following disclaimer.
-// 2. Redistributions in binary form must reproduce the above copyright notice,
-//    this list of conditions and the following disclaimer in the documentation
-//    and/or other materials provided with the distribution.
-// 3. Neither the name of the Skulltag Development Team nor the names of its
-//    contributors may be used to endorse or promote products derived from this
-//    software without specific prior written permission.
-// 4. Redistributions in any form must be accompanied by information on how to
-//    obtain complete source code for the software and any accompanying
-//    software that uses the software. The source code must either be included
-//    in the distribution or be available for no more than the cost of
-//    distribution plus a nominal fee, and must be freely redistributable
-//    under reasonable conditions. For an executable file, complete source
-//    code means the source code for all modules it contains. It does not
-//    include source code for modules or files that typically accompany the
-//    major components of the operating system on which the executable file
-//    runs.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
-// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
-// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
-// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
-// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
-// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
-// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
-// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
-// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
-// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-// POSSIBILITY OF SUCH DAMAGE.
-//
-//
-//
-// Filename: bots.h
-//
-// Description: Contains bot structures and prototypes
-// [Dusk] Cropped out the stuff botc doesn't need.
-//
-//-----------------------------------------------------------------------------
-
-#ifndef __BOTS_H__
-#define __BOTS_H__
-
-//*****************************************************************************
-//  DEFINES
-
-// Maximum number of variables on the bot evaluation stack.
-#define	BOTSCRIPT_STACK_SIZE		8
-
-// Maximum number of botinto structures that can be defines.
-#define	MAX_BOTINFO					128
-
-// Maximum number of states that can appear in a script.
-#define	MAX_NUM_STATES				256
-
-// Maximum number of bot events that can be defined.
-#define	MAX_NUM_EVENTS				32
-
-// Maximum number of global bot events that can be defined.
-#define	MAX_NUM_GLOBAL_EVENTS		32
-
-// Maximum number of global variables that can be defined in a script.
-#define	MAX_SCRIPT_VARIABLES		128
-
-// Maximum number of global arrays that can be defined in a script.
-#define	MAX_SCRIPT_ARRAYS			16
-
-// Maximum number of global arrays that can be defined in a script.
-#define	MAX_SCRIPTARRAY_SIZE		65536
-
-// Maxmimum number of state (local) variables that can appear in a script.
-#define	MAX_STATE_VARIABLES			16
-
-// Maximum number of strings that can appear in a script stringlist.
-#define	MAX_LIST_STRINGS			128
-
-// Maximum length of those strings in the stringlist.
-#define	MAX_STRING_LENGTH			256
-
-// Maximum reaction time for a bot.
-#define	MAX_REACTION_TIME			52
-
-// Maximum number of events the bots can store up that it's waiting to react to.
-#define	MAX_STORED_EVENTS			64
-
-//*****************************************************************************
-typedef enum
-{
-	// Bot skill ratings.
-	BOTSKILL_VERYPOOR,
-	BOTSKILL_POOR,
-	BOTSKILL_LOW,
-	BOTSKILL_MEDIUM,
-	BOTSKILL_HIGH,
-	BOTSKILL_EXCELLENT,
-	BOTSKILL_SUPREME,
-	BOTSKILL_GODLIKE,
-	BOTSKILL_PERFECT,
-
-	NUM_BOT_SKILLS
-
-} BOTSKILL_e;
-
-//*****************************************************************************
-//  STRUCTURES
-//
-
-//*****************************************************************************
-//	These are the botscript data headers that it writes out.
-typedef enum
-{
-	DH_COMMAND,
-	DH_STATEIDX,
-	DH_STATENAME,
-	DH_ONENTER,
-	DH_MAINLOOP,
-	DH_ONEXIT,
-	DH_EVENT,
-	DH_ENDONENTER,
-	DH_ENDMAINLOOP,
-	DH_ENDONEXIT,
-	DH_ENDEVENT,
-	DH_IFGOTO,
-	DH_IFNOTGOTO,
-	DH_GOTO,
-	DH_ORLOGICAL,
-	DH_ANDLOGICAL,
-	DH_ORBITWISE,
-	DH_EORBITWISE,
-	DH_ANDBITWISE,
-	DH_EQUALS,
-	DH_NOTEQUALS,
-	DH_LESSTHAN,
-	DH_LESSTHANEQUALS,
-	DH_GREATERTHAN,
-	DH_GREATERTHANEQUALS,
-	DH_NEGATELOGICAL,
-	DH_LSHIFT,
-	DH_RSHIFT,
-	DH_ADD,
-	DH_SUBTRACT,
-	DH_UNARYMINUS,
-	DH_MULTIPLY,
-	DH_DIVIDE,
-	DH_MODULUS,
-	DH_PUSHNUMBER,
-	DH_PUSHSTRINGINDEX,
-	DH_PUSHGLOBALVAR,
-	DH_PUSHLOCALVAR,
-	DH_DROPSTACKPOSITION,
-	DH_SCRIPTVARLIST,
-	DH_STRINGLIST,
-	DH_INCGLOBALVAR,
-	DH_DECGLOBALVAR,
-	DH_ASSIGNGLOBALVAR,
-	DH_ADDGLOBALVAR,
-	DH_SUBGLOBALVAR,
-	DH_MULGLOBALVAR,
-	DH_DIVGLOBALVAR,
-	DH_MODGLOBALVAR,
-	DH_INCLOCALVAR,
-	DH_DECLOCALVAR,
-	DH_ASSIGNLOCALVAR,
-	DH_ADDLOCALVAR,
-	DH_SUBLOCALVAR,
-	DH_MULLOCALVAR,
-	DH_DIVLOCALVAR,
-	DH_MODLOCALVAR,
-	DH_CASEGOTO,
-	DH_DROP,
-	DH_INCGLOBALARRAY,
-	DH_DECGLOBALARRAY,
-	DH_ASSIGNGLOBALARRAY,
-	DH_ADDGLOBALARRAY,
-	DH_SUBGLOBALARRAY,
-	DH_MULGLOBALARRAY,
-	DH_DIVGLOBALARRAY,
-	DH_MODGLOBALARRAY,
-	DH_PUSHGLOBALARRAY,
-	DH_SWAP,
-	DH_DUP,
-	DH_ARRAYSET,
-
-	NUM_DATAHEADERS
-
-} DATAHEADERS_e;
-
-//*****************************************************************************
-//	These are the different bot events that can be posted to a bot's state.
-typedef enum
-{
-	BOTEVENT_KILLED_BYENEMY,
-	BOTEVENT_KILLED_BYPLAYER,
-	BOTEVENT_KILLED_BYSELF,
-	BOTEVENT_KILLED_BYENVIORNMENT,
-	BOTEVENT_REACHED_GOAL,
-	BOTEVENT_GOAL_REMOVED,
-	BOTEVENT_DAMAGEDBY_PLAYER,
-	BOTEVENT_PLAYER_SAY,
-	BOTEVENT_ENEMY_KILLED,
-	BOTEVENT_RESPAWNED,
-	BOTEVENT_INTERMISSION,
-	BOTEVENT_NEWMAP,
-	BOTEVENT_ENEMY_USEDFIST,
-	BOTEVENT_ENEMY_USEDCHAINSAW,
-	BOTEVENT_ENEMY_FIREDPISTOL,
-	BOTEVENT_ENEMY_FIREDSHOTGUN,
-	BOTEVENT_ENEMY_FIREDSSG,
-	BOTEVENT_ENEMY_FIREDCHAINGUN,
-	BOTEVENT_ENEMY_FIREDMINIGUN,
-	BOTEVENT_ENEMY_FIREDROCKET,
-	BOTEVENT_ENEMY_FIREDGRENADE,
-	BOTEVENT_ENEMY_FIREDRAILGUN,
-	BOTEVENT_ENEMY_FIREDPLASMA,
-	BOTEVENT_ENEMY_FIREDBFG,
-	BOTEVENT_ENEMY_FIREDBFG10K,
-	BOTEVENT_PLAYER_USEDFIST,
-	BOTEVENT_PLAYER_USEDCHAINSAW,
-	BOTEVENT_PLAYER_FIREDPISTOL,
-	BOTEVENT_PLAYER_FIREDSHOTGUN,
-	BOTEVENT_PLAYER_FIREDSSG,
-	BOTEVENT_PLAYER_FIREDCHAINGUN,
-	BOTEVENT_PLAYER_FIREDMINIGUN,
-	BOTEVENT_PLAYER_FIREDROCKET,
-	BOTEVENT_PLAYER_FIREDGRENADE,
-	BOTEVENT_PLAYER_FIREDRAILGUN,
-	BOTEVENT_PLAYER_FIREDPLASMA,
-	BOTEVENT_PLAYER_FIREDBFG,
-	BOTEVENT_PLAYER_FIREDBFG10K,
-	BOTEVENT_USEDFIST,
-	BOTEVENT_USEDCHAINSAW,
-	BOTEVENT_FIREDPISTOL,
-	BOTEVENT_FIREDSHOTGUN,
-	BOTEVENT_FIREDSSG,
-	BOTEVENT_FIREDCHAINGUN,
-	BOTEVENT_FIREDMINIGUN,
-	BOTEVENT_FIREDROCKET,
-	BOTEVENT_FIREDGRENADE,
-	BOTEVENT_FIREDRAILGUN,
-	BOTEVENT_FIREDPLASMA,
-	BOTEVENT_FIREDBFG,
-	BOTEVENT_FIREDBFG10K,
-	BOTEVENT_PLAYER_JOINEDGAME,
-	BOTEVENT_JOINEDGAME,
-	BOTEVENT_DUEL_STARTINGCOUNTDOWN,
-	BOTEVENT_DUEL_FIGHT,
-	BOTEVENT_DUEL_WINSEQUENCE,
-	BOTEVENT_SPECTATING,
-	BOTEVENT_LMS_STARTINGCOUNTDOWN,
-	BOTEVENT_LMS_FIGHT,
-	BOTEVENT_LMS_WINSEQUENCE,
-	BOTEVENT_WEAPONCHANGE,
-	BOTEVENT_ENEMY_BFGEXPLODE,
-	BOTEVENT_PLAYER_BFGEXPLODE,
-	BOTEVENT_BFGEXPLODE,
-	BOTEVENT_RECEIVEDMEDAL,
-
-	NUM_BOTEVENTS
-
-} BOTEVENT_e;
-
-#endif	// __BOTS_H__
--- a/commands.cxx	Wed Jan 02 23:57:46 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,217 +0,0 @@
-/*
- *	botc source code
- *	Copyright (C) 2012 Santeri `Dusk` Piippo
- *	All rights reserved.
- *	
- *	Redistribution and use in source and binary forms, with or without
- *	modification, are permitted provided that the following conditions are met:
- *	
- *	1. Redistributions of source code must retain the above copyright notice,
- *	   this list of conditions and the following disclaimer.
- *	2. Redistributions in binary form must reproduce the above copyright notice,
- *	   this list of conditions and the following disclaimer in the documentation
- *	   and/or other materials provided with the distribution.
- *	3. Neither the name of the developer nor the names of its contributors may
- *	   be used to endorse or promote products derived from this software without
- *	   specific prior written permission.
- *	4. Redistributions in any form must be accompanied by information on how to
- *	   obtain complete source code for the software and any accompanying
- *	   software that uses the software. The source code must either be included
- *	   in the distribution or be available for no more than the cost of
- *	   distribution plus a nominal fee, and must be freely redistributable
- *	   under reasonable conditions. For an executable file, complete source
- *	   code means the source code for all modules it contains. It does not
- *	   include source code for modules or files that typically accompany the
- *	   major components of the operating system on which the executable file
- *	   runs.
- *	
- *	THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- *	AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- *	IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- *	ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
- *	LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- *	CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- *	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- *	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- *	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- *	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- *	POSSIBILITY OF SUCH DAMAGE.
- */
-
-#define __COMMANDS_CXX__
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include "common.h"
-#include "scriptreader.h"
-#include "str.h"
-#include "commands.h"
-
-// ============================================================================
-// Reads command definitions from commands.def and stores them to memory.
-void ReadCommands () {
-	ScriptReader* r = new ScriptReader ("commands.def");
-	g_CommDef = NULL;
-	CommandDef* curdef = g_CommDef;
-	unsigned int numCommDefs = 0;
-	
-	while (r->PeekNext().len()) {
-		CommandDef* comm = new CommandDef;
-		comm->next = NULL;
-		
-		// Number
-		r->MustNumber ();
-		comm->number = r->token;
-		
-		r->MustNext (":");
-		
-		// Name
-		r->MustNext ();
-		comm->name = r->token;
-		if (IsKeyword (comm->name))
-			r->ParserError ("command name `%s` conflicts with keyword", comm->name.chars());
-		
-		r->MustNext (":");
-		
-		// Return value
-		r->MustNext ();
-		comm->returnvalue = GetTypeByName (r->token);
-		if (comm->returnvalue == -1)
-			r->ParserError ("bad return value type `%s` for command %s", r->token.chars(), comm->name.chars());
-		
-		r->MustNext (":");
-		
-		// Num args
-		r->MustNumber ();
-		comm->numargs = r->token;
-		
-		r->MustNext (":");
-		
-		// Max args
-		r->MustNumber ();
-		comm->maxargs = r->token;
-		
-		if (comm->maxargs > MAX_MAXARGS)
-			r->ParserError ("maxargs (%d) greater than %d!", comm->maxargs, MAX_MAXARGS);
-		
-		// Argument types
-		int curarg = 0;
-		while (curarg < comm->maxargs) {
-			r->MustNext (":");
-			r->MustNext ();
-			
-			type_e type = GetTypeByName (r->token);
-			if (type == -1)
-				r->ParserError ("bad argument %d type `%s`", curarg, r->token.chars());
-			if (type == TYPE_VOID)
-				r->ParserError ("void is not a valid argument type!");
-			comm->argtypes[curarg] = type;
-			
-			r->MustNext ("(");
-			r->MustNext ();
-			
-			// - 1 because of terminating null character
-			if (r->token.len() > MAX_ARGNAMELEN - 1)
-				r->ParserWarning ("argument name is too long (%d, max is %d)",
-					r->token.len(), MAX_ARGNAMELEN - 1);
-			
-			strncpy (comm->argnames[curarg], r->token.chars(), MAX_ARGNAMELEN);
-			comm->argnames[curarg][MAX_ARGNAMELEN-1] = 0;
-			
-			// If this is an optional parameter, we need the default value.
-			if (curarg >= comm->numargs) {
-				r->MustNext ("=");
-				switch (type) {
-				case TYPE_INT:
-				case TYPE_BOOL:
-					r->MustNumber();
-					break;
-				case TYPE_STRING:
-					r->MustString();
-					break;
-				case TYPE_UNKNOWN:
-				case TYPE_VOID:
-					break;
-				}
-				
-				comm->defvals[curarg] = r->token;
-			}
-			
-			r->MustNext (")");
-			curarg++;
-		}
-		
-		if (!g_CommDef)
-			g_CommDef = comm;
-		
-		if (!curdef) {
-			curdef = comm;
-		} else {
-			curdef->next = comm;
-			curdef = comm;
-		}
-		numCommDefs++;
-	}
-	
-	if (!numCommDefs)
-		r->ParserError ("no commands defined!\n");
-	
-	r->CloseFile ();
-	delete r;
-	printf ("%d command definitions read.\n", numCommDefs);
-}
-
-// ============================================================================
-// Finds a command by name
-CommandDef* FindCommand (str fname) {
-	CommandDef* comm;
-	ITERATE_COMMANDS (comm) {
-		if (!fname.icompare (comm->name))
-			return comm;
-	}
-	
-	return NULL;
-}
-
-// ============================================================================
-// Returns the prototype of the command
-str GetCommandPrototype (CommandDef* comm) {
-	str text;
-	text += GetTypeName (comm->returnvalue);
-	text += ' ';
-	text += comm->name;
-	text += '(';
-	
-	bool hasOptionalArguments = false;
-	for (int i = 0; i < comm->maxargs; i++) {
-		if (i == comm->numargs) {
-			hasOptionalArguments = true;
-			text += '[';
-		}
-		
-		if (i)
-			text += ", ";
-		
-		text += GetTypeName (comm->argtypes[i]);
-		text += ' ';
-		text += comm->argnames[i];
-		
-		if (i >= comm->numargs) {
-			text += '=';
-			
-			bool isString = comm->argtypes[i] == TYPE_STRING;
-			if (isString) text += '"';
-			
-			char defvalstring[8];
-			sprintf (defvalstring, "%d", comm->defvals[i]);
-			text += defvalstring;
-			
-			if (isString) text += '"';
-		}
-	}
-	
-	if (hasOptionalArguments)
-		text += ']';
-	text += ')';
-	return text;
-}
\ No newline at end of file
--- a/commands.h	Wed Jan 02 23:57:46 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,75 +0,0 @@
-/*
- *	botc source code
- *	Copyright (C) 2012 Santeri `Dusk` Piippo
- *	All rights reserved.
- *	
- *	Redistribution and use in source and binary forms, with or without
- *	modification, are permitted provided that the following conditions are met:
- *	
- *	1. Redistributions of source code must retain the above copyright notice,
- *	   this list of conditions and the following disclaimer.
- *	2. Redistributions in binary form must reproduce the above copyright notice,
- *	   this list of conditions and the following disclaimer in the documentation
- *	   and/or other materials provided with the distribution.
- *	3. Neither the name of the developer nor the names of its contributors may
- *	   be used to endorse or promote products derived from this software without
- *	   specific prior written permission.
- *	4. Redistributions in any form must be accompanied by information on how to
- *	   obtain complete source code for the software and any accompanying
- *	   software that uses the software. The source code must either be included
- *	   in the distribution or be available for no more than the cost of
- *	   distribution plus a nominal fee, and must be freely redistributable
- *	   under reasonable conditions. For an executable file, complete source
- *	   code means the source code for all modules it contains. It does not
- *	   include source code for modules or files that typically accompany the
- *	   major components of the operating system on which the executable file
- *	   runs.
- *	
- *	THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- *	AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- *	IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- *	ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
- *	LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- *	CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- *	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- *	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- *	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- *	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- *	POSSIBILITY OF SUCH DAMAGE.
-*/
-
-#ifndef __COMMANDS_H__
-#define __COMMANDS_H__
-
-#define MAX_MAXARGS 8
-#define MAX_ARGNAMELEN 16
-
-#include "common.h"
-#include "str.h"
-#include "botcommands.h"
-
-#define ITERATE_COMMANDS(comm) \
-	for (comm = g_CommDef; comm->next != NULL; comm = comm->next)
-
-struct CommandDef {
-	str name;
-	int number;
-	int numargs;
-	int maxargs;
-	type_e returnvalue;
-	type_e argtypes[MAX_MAXARGS];
-	char argnames[MAX_MAXARGS][MAX_ARGNAMELEN];
-	int defvals[MAX_MAXARGS];
-	CommandDef* next;
-};
-
-void ReadCommands ();
-CommandDef* FindCommand (str a);
-str GetCommandPrototype (CommandDef* comm);
-
-#ifndef __COMMANDS_CXX__
-extern
-#endif
-CommandDef* g_CommDef;
-
-#endif // __COMMANDS_H__
\ No newline at end of file
--- a/common.h	Wed Jan 02 23:57:46 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,186 +0,0 @@
-/*
- *	botc source code
- *	Copyright (C) 2012 Santeri `Dusk` Piippo
- *	All rights reserved.
- *	
- *	Redistribution and use in source and binary forms, with or without
- *	modification, are permitted provided that the following conditions are met:
- *	
- *	1. Redistributions of source code must retain the above copyright notice,
- *	   this list of conditions and the following disclaimer.
- *	2. Redistributions in binary form must reproduce the above copyright notice,
- *	   this list of conditions and the following disclaimer in the documentation
- *	   and/or other materials provided with the distribution.
- *	3. Neither the name of the developer nor the names of its contributors may
- *	   be used to endorse or promote products derived from this software without
- *	   specific prior written permission.
- *	4. Redistributions in any form must be accompanied by information on how to
- *	   obtain complete source code for the software and any accompanying
- *	   software that uses the software. The source code must either be included
- *	   in the distribution or be available for no more than the cost of
- *	   distribution plus a nominal fee, and must be freely redistributable
- *	   under reasonable conditions. For an executable file, complete source
- *	   code means the source code for all modules it contains. It does not
- *	   include source code for modules or files that typically accompany the
- *	   major components of the operating system on which the executable file
- *	   runs.
- *	
- *	THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- *	AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- *	IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- *	ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
- *	LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- *	CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- *	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- *	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- *	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- *	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- *	POSSIBILITY OF SUCH DAMAGE.
-*/
-
-#ifndef __COMMON_H__
-#define __COMMON_H__
-
-#include <stdio.h>
-#include <stdarg.h>
-#include <stdint.h>
-#include "bots.h"
-#include "str.h"
-
-// Application name and version
-#define APPNAME "botc"
-#define VERSION_MAJOR 0
-#define VERSION_MINOR 999
-
-// Use a macro for Write so we can get the function name
-// This can be pretty crucial in debugging.
-#ifdef __GNUC__
-#define Write(STUFF) DoWrite (__PRETTY_FUNCTION__, STUFF)
-#else
-#define Write(STUFF) DoWrite (__func__, STUFF)
-#endif
-
-// On Windows, files are case-insensitive
-#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32)) && !defined(__CYGWIN__)
-	#define FILE_CASEINSENSITIVE
-#endif
-
-// Parser mode: where is the parser at?
-enum parsermode_e {
-	MODE_TOPLEVEL,	// at top level
-	MODE_EVENT,		// inside event definition
-	MODE_MAINLOOP,	// inside mainloop
-	MODE_ONENTER,	// inside onenter
-	MODE_ONEXIT,	// inside onexit
-};
-
-enum type_e {
-	TYPE_UNKNOWN = 0,
-	TYPE_VOID,
-	TYPE_INT,
-	TYPE_STRING,
-	TYPE_BOOL,
-};
-
-#define CHECK_FILE(pointer,path,action) \
-	if (!pointer) { \
-		error ("couldn't open %s for %s!\n", (char*)path, action); \
-		exit (1); \
-	}
-
-// Shortcut for formatting
-#define PERFORM_FORMAT(in, out) \
-	va_list v; \
-	va_start (v, in); \
-	char* out = vdynformat (in, v, 256); \
-	va_end (v);
-
-// Plural expression
-#define PLURAL(n) (n != 1) ? "s" : ""
-
-// Shortcut for zeroing something
-#define ZERO(obj) memset (&obj, 0, sizeof (obj));
-
-void error (const char* text, ...);
-char* ObjectFileName (str s);
-bool fexists (char* path);
-type_e GetTypeByName (str token);
-str GetTypeName (type_e type);
-
-// Make the parser's variables globally available
-extern int g_NumStates;
-extern int g_NumEvents;
-extern parsermode_e g_CurMode;
-extern str g_CurState;
-
-#define neurosphere if (g_Neurosphere)
-#define twice for (int repeat_token = 0; repeat_token < 2; repeat_token++)
-
-#ifndef __GNUC__
-#define __attribute__(X)
-#endif
-#define deprecated __attribute__ ((deprecated))
-
-// Power function
-template<class T> T pow (T a, unsigned int b) {
-	if (!b)
-		return 1;
-	
-	T r = a;
-	while (b > 1) {
-		b--;
-		r = r * a;
-	}
-	
-	return r;
-}
-
-// Whitespace check
-inline bool IsCharWhitespace (char c) {
-	return (c <= 32 || c == 127 || c == 255);
-}
-
-// Byte datatype
-typedef int32_t word;
-typedef unsigned char byte;
-
-// Keywords
-#ifndef __MAIN_CXX__
-extern const char** g_Keywords;
-#endif
-
-bool IsKeyword (str s);
-unsigned int NumKeywords ();
-
-// Script mark and reference
-struct ScriptMark {
-	str name;
-	size_t pos;
-};
-
-struct ScriptMarkReference {
-	unsigned int num;
-	size_t pos;
-};
-
-// ====================================================================
-// Generic union
-template <class T> union union_t {
-	T val;
-	byte b[sizeof (T)];
-	char c[sizeof (T)];
-	double d;
-	float f;
-	int i;
-	word w;
-};
-
-// ====================================================================
-// Finds a byte in the given value.
-template <class T> inline unsigned char GetByteIndex (T a, unsigned int b) {
-	union_t<T> uni;
-	uni.val = a;
-	return uni.b[b];
-}
-
-#endif // __COMMON_H__
--- a/databuffer.h	Wed Jan 02 23:57:46 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,303 +0,0 @@
-/*
- *	botc source code
- *	Copyright (C) 2012 Santeri `Dusk` Piippo
- *	All rights reserved.
- *	
- *	Redistribution and use in source and binary forms, with or without
- *	modification, are permitted provided that the following conditions are met:
- *	
- *	1. Redistributions of source code must retain the above copyright notice,
- *	   this list of conditions and the following disclaimer.
- *	2. Redistributions in binary form must reproduce the above copyright notice,
- *	   this list of conditions and the following disclaimer in the documentation
- *	   and/or other materials provided with the distribution.
- *	3. Neither the name of the developer nor the names of its contributors may
- *	   be used to endorse or promote products derived from this software without
- *	   specific prior written permission.
- *	4. Redistributions in any form must be accompanied by information on how to
- *	   obtain complete source code for the software and any accompanying
- *	   software that uses the software. The source code must either be included
- *	   in the distribution or be available for no more than the cost of
- *	   distribution plus a nominal fee, and must be freely redistributable
- *	   under reasonable conditions. For an executable file, complete source
- *	   code means the source code for all modules it contains. It does not
- *	   include source code for modules or files that typically accompany the
- *	   major components of the operating system on which the executable file
- *	   runs.
- *	
- *	THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- *	AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- *	IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- *	ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
- *	LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- *	CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- *	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- *	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- *	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- *	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- *	POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef  __DATABUFFER_H__
-#define __DATABUFFER_H__
-#include <stdio.h>
-#include <string.h>
-#include "common.h"
-#include "stringtable.h"
-
-#define MAX_MARKS 512
-
-extern int g_NextMark;
-
-// ============================================================================
-// DataBuffer: A dynamic data buffer.
-class DataBuffer {
-public:
-	// The actual buffer
-	byte* buffer;
-	
-	// Allocated size of the buffer
-	unsigned int allocsize;
-	
-	// Written size of the buffer
-	unsigned int writesize;
-	
-	// Marks and references
-	ScriptMark* marks[MAX_MARKS];
-	ScriptMarkReference* refs[MAX_MARKS];
-	
-	// ====================================================================
-	// METHODS
-	
-	// ====================================================================
-	// Constructor
-	DataBuffer (unsigned int size=128) {
-		writesize = 0;
-		
-		buffer = new unsigned char[size];
-		allocsize = size;
-		
-		// Clear the marks table out
-		for (unsigned int u = 0; u < MAX_MARKS; u++) {
-			marks[u] = NULL;
-			refs[u] = NULL;
-		}
-	}
-	
-	// ====================================================================
-	~DataBuffer () {
-		delete buffer;
-		
-		// Delete any marks and references
-		for (unsigned int u = 0; u < MAX_MARKS; u++) {
-			if (marks[u])
-				delete marks[u];
-			
-			if (refs[u])
-				delete refs[u];
-		}
-	}
-	
-	// ====================================================================
-	// Write stuff to the buffer
-	template<class T> void DoWrite (const char* func, T stuff) {
-		// printf ("DoWrite: called from %s\n", func);
-		if (writesize + sizeof (T) >= allocsize) {
-			// We don't have enough space in the buffer to write
-			// the stuff - thus resize. First, store the old
-			// buffer temporarily:
-			char* copy = new char[allocsize];
-			memcpy (copy, buffer, allocsize);
-			
-			// Remake the buffer with the new size. Have enough space
-			// for the stuff we're going to write, as well as a bit
-			// of leeway so we don't have to resize immediately again.
-			size_t newsize = allocsize + sizeof (T) + 128;
-			
-			delete buffer;
-			buffer = new unsigned char[newsize];
-			allocsize = newsize;
-			
-			// Now, copy the stuff back.
-			memcpy (buffer, copy, allocsize);
-			delete copy;
-		}
-		
-		// Buffer is now guaranteed to have enough space.
-		// Write the stuff one byte at a time.
-		union_t<T> uni;
-		uni.val = stuff;
-		for (unsigned int x = 0; x < sizeof (T); x++) {
-			if (writesize >= allocsize) // should NEVER happen because resizing is done above
-				error ("DataBuffer: written size exceeds allocated size!\n");
-			
-			buffer[writesize] = uni.b[x];
-			writesize++;
-		}
-	}
-	
-	// ====================================================================
-	// Merge another data buffer into this one.
-	void Merge (DataBuffer* other) {
-		if (!other)
-			return;
-		int oldsize = writesize;
-		
-		for (unsigned int x = 0; x < other->writesize; x++)
-			Write (*(other->buffer+x));
-		
-		// Merge its marks and references
-		unsigned int u = 0;
-		for (u = 0; u < MAX_MARKS; u++) {
-			if (other->marks[u]) {
-				// Merge the mark and offset its position.
-				if (marks[u])
-					error ("DataBuffer: duplicate mark %d!\n");
-				
-				marks[u] = other->marks[u];
-				marks[u]->pos += oldsize;
-				
-				// The original mark becomes NULL so that the deconstructor
-				// will not delete it prematurely. (should it delete any
-				// marks in the first place since there is no such thing
-				// as at temporary mark?)
-				other->marks[u] = NULL;
-			}
-			
-			if (other->refs[u]) {
-				// Same for references
-				// TODO: add a g_NextRef system like here, akin to marks!
-				unsigned int r = AddMarkReference (other->refs[u]->num, false);
-				refs[r]->pos = other->refs[u]->pos + oldsize;
-			}
-		}
-		
-		delete other;
-	}
-	
-	// Clones this databuffer to a new one and returns it.
-	DataBuffer* Clone () {
-		DataBuffer* other = new DataBuffer;
-		for (unsigned int x = 0; x < writesize; x++)
-			other->Write (*(buffer+x));
-		return other;
-	}
-	
-	// ====================================================================
-	// Adds a mark to the buffer. A mark is a "pointer" to a particular
-	// position in the bytecode. The actual permanent position cannot
-	// be predicted in any way or form, thus these things will be used
-	// to "mark" a position like that for future use.
-	unsigned int AddMark (str name) {
-		// Find a free slot for the mark
-		unsigned int u = g_NextMark++;
-		
-		if (marks[u])
-			error ("DataBuffer: attempted to re-create mark %u!\n", u);
-		
-		if (u >= MAX_MARKS)
-			error ("mark quota exceeded, all labels, if-structs and loops add marks\n");
-		
-		ScriptMark* m = new ScriptMark;
-		m->name = name;
-		m->pos = writesize;
-		marks[u] = m;
-		return u;
-	}
-	
-	// ====================================================================
-	// A ref is another "mark" that references a mark. When the bytecode
-	// is written to file, they are changed into their marks' current
-	// positions. Marks themselves are never written to files, only refs are
-	unsigned int AddMarkReference (unsigned int marknum, bool placeholder = true) {
-		unsigned int u;
-		for (u = 0; u < MAX_MARKS; u++)
-			if (!refs[u])
-				break;
-		
-		if (u == MAX_MARKS)
-			error ("mark reference quota exceeded, all goto-statements, if-structs and loops add refs\n");
-		
-		ScriptMarkReference* r = new ScriptMarkReference;
-		r->num = marknum;
-		r->pos = writesize;
-		refs[u] = r;
-		
-		// Write a dummy placeholder for the reference
-		if (placeholder)
-			Write (1234);
-		
-		return u;
-	}
-	
-	// Delete a mark and all references to it.
-	void DeleteMark (unsigned int marknum) {
-		if (!marks[marknum])
-			return;
-		
-		// Delete the mark
-		delete marks[marknum];
-		marks[marknum] = NULL;
-		
-		// Delete its references
-		for (unsigned int u = 0; u < MAX_MARKS; u++) {
-			if (refs[u]->num == marknum) {
-				delete refs[u];
-				refs[u] = NULL;
-			}
-		}
-	}
-	
-	// Adjusts a mark to the current position
-	void MoveMark (unsigned int mark, int offset = -1) {
-		if (!marks[mark])
-			return;
-		marks[mark]->pos = writesize;
-	}
-	
-	void OffsetMark (unsigned int mark, size_t offset) {
-		if (!marks[mark])
-			return;
-		marks[mark]->pos += offset;
-	}
-	
-	// Dump the buffer (for debugging purposes)
-	void Dump() {
-		for (unsigned int x = 0; x < writesize; x++)
-			printf ("%d. [%d]\n", x, *(buffer+x));
-	}
-	
-	// Count the amount of marks
-	unsigned int CountMarks () {
-		unsigned int count = 0;
-		for (unsigned int u = 0; u < MAX_MARKS; u++)
-			count += !!marks[u];
-		return count;
-	}
-	
-	// Count the amount of refs
-	unsigned int CountReferences () {
-		unsigned int count = 0;
-		for (unsigned int u = 0; u < MAX_MARKS; u++)
-			count += !!refs[u];
-		return count;
-	}
-	
-	// Write a float into the buffer
-	void WriteFloat (str floatstring) {
-		// TODO: Casting float to word causes the decimal to be lost.
-		// Find a way to store the number without such loss.
-		float val = atof (floatstring);
-		Write (DH_PUSHNUMBER);
-		Write (static_cast<word> ((val > 0) ? val : -val));
-		if (val < 0)
-			Write (DH_UNARYMINUS);
-	}
-	
-	void WriteString (str string) {
-		Write (DH_PUSHSTRINGINDEX);
-		Write (PushToStringTable (string));
-	}
-};
-
-#endif // __DATABUFFER_H__
\ No newline at end of file
--- a/events.cxx	Wed Jan 02 23:57:46 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,112 +0,0 @@
-/*
- *	botc source code
- *	Copyright (C) 2012 Santeri `Dusk` Piippo
- *	All rights reserved.
- *	
- *	Redistribution and use in source and binary forms, with or without
- *	modification, are permitted provided that the following conditions are met:
- *	
- *	1. Redistributions of source code must retain the above copyright notice,
- *	   this list of conditions and the following disclaimer.
- *	2. Redistributions in binary form must reproduce the above copyright notice,
- *	   this list of conditions and the following disclaimer in the documentation
- *	   and/or other materials provided with the distribution.
- *	3. Neither the name of the developer nor the names of its contributors may
- *	   be used to endorse or promote products derived from this software without
- *	   specific prior written permission.
- *	4. Redistributions in any form must be accompanied by information on how to
- *	   obtain complete source code for the software and any accompanying
- *	   software that uses the software. The source code must either be included
- *	   in the distribution or be available for no more than the cost of
- *	   distribution plus a nominal fee, and must be freely redistributable
- *	   under reasonable conditions. For an executable file, complete source
- *	   code means the source code for all modules it contains. It does not
- *	   include source code for modules or files that typically accompany the
- *	   major components of the operating system on which the executable file
- *	   runs.
- *	
- *	THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- *	AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- *	IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- *	ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
- *	LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- *	CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- *	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- *	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- *	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- *	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- *	POSSIBILITY OF SUCH DAMAGE.
- */
-
-#define __EVENTS_CXX__
-#include <stdlib.h>
-#include <stdio.h>
-#include "common.h"
-#include "scriptreader.h"
-#include "str.h"
-#include "events.h"
-
-EventDef* g_EventDef;
-
-// ============================================================================
-// Read event definitions from file
-void ReadEvents () {
-	ScriptReader* r = new ScriptReader ("events.def");
-	g_EventDef = NULL;
-	EventDef* curdef = g_EventDef;
-	unsigned int numEventDefs = 0;
-	while (r->Next()) {
-		EventDef* e = new EventDef;
-		e->name = r->token;
-		e->number = numEventDefs;
-		e->next = NULL;
-		
-		// g_EventDef becomes the first eventdef
-		if (!g_EventDef)
-			g_EventDef = e;
-		
-		if (!curdef) {
-			curdef = e;
-		} else {
-			curdef->next = e;
-			curdef = e;
-		}
-		numEventDefs++;
-	}
-	
-	delete r;
-	printf ("%d event definitions read.\n", numEventDefs);
-}
-
-// ============================================================================
-// Delete event definitions recursively
-void UnlinkEvents (EventDef* e) {
-	if (e->next)
-		UnlinkEvents (e->next);
-	delete e;
-}
-
-// ============================================================================
-// Finds an event definition by index
-EventDef* FindEventByIdx (unsigned int idx) {
-	EventDef* e = g_EventDef;
-	while (idx > 0) {
-		if (!e->next)
-			return NULL;
-		e = e->next;
-		idx--;
-	}
-	return e;
-}
-
-// ============================================================================
-// Finds an event definition by name
-EventDef* FindEventByName (str a) {
-	EventDef* e;
-	for (e = g_EventDef; e->next != NULL; e = e->next) {
-		if (!a.icompare (e->name))
-			return e;
-	}
-	
-	return NULL;
-}
\ No newline at end of file
--- a/events.h	Wed Jan 02 23:57:46 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,57 +0,0 @@
-/*
- *	botc source code
- *	Copyright (C) 2012 Santeri `Dusk` Piippo
- *	All rights reserved.
- *	
- *	Redistribution and use in source and binary forms, with or without
- *	modification, are permitted provided that the following conditions are met:
- *	
- *	1. Redistributions of source code must retain the above copyright notice,
- *	   this list of conditions and the following disclaimer.
- *	2. Redistributions in binary form must reproduce the above copyright notice,
- *	   this list of conditions and the following disclaimer in the documentation
- *	   and/or other materials provided with the distribution.
- *	3. Neither the name of the developer nor the names of its contributors may
- *	   be used to endorse or promote products derived from this software without
- *	   specific prior written permission.
- *	4. Redistributions in any form must be accompanied by information on how to
- *	   obtain complete source code for the software and any accompanying
- *	   software that uses the software. The source code must either be included
- *	   in the distribution or be available for no more than the cost of
- *	   distribution plus a nominal fee, and must be freely redistributable
- *	   under reasonable conditions. For an executable file, complete source
- *	   code means the source code for all modules it contains. It does not
- *	   include source code for modules or files that typically accompany the
- *	   major components of the operating system on which the executable file
- *	   runs.
- *	
- *	THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- *	AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- *	IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- *	ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
- *	LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- *	CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- *	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- *	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- *	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- *	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- *	POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef __EVENT_H__
-#define __EVENT_H__
-
-#include "str.h"
-
-struct EventDef {
-	str name;
-	int number;
-	EventDef* next;
-};
-
-void ReadEvents ();
-void UnlinkEvents (EventDef* e);
-EventDef* FindEventByIdx (unsigned int idx);
-EventDef* FindEventByName (str a);
-
-#endif // __EVENT_H__
\ No newline at end of file
--- a/main.cxx	Wed Jan 02 23:57:46 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,273 +0,0 @@
-/*
- *	botc source code
- *	Copyright (C) 2012 Santeri `Dusk` Piippo
- *	All rights reserved.
- *	
- *	Redistribution and use in source and binary forms, with or without
- *	modification, are permitted provided that the following conditions are met:
- *	
- *	1. Redistributions of source code must retain the above copyright notice,
- *	   this list of conditions and the following disclaimer.
- *	2. Redistributions in binary form must reproduce the above copyright notice,
- *	   this list of conditions and the following disclaimer in the documentation
- *	   and/or other materials provided with the distribution.
- *	3. Neither the name of the developer nor the names of its contributors may
- *	   be used to endorse or promote products derived from this software without
- *	   specific prior written permission.
- *	4. Redistributions in any form must be accompanied by information on how to
- *	   obtain complete source code for the software and any accompanying
- *	   software that uses the software. The source code must either be included
- *	   in the distribution or be available for no more than the cost of
- *	   distribution plus a nominal fee, and must be freely redistributable
- *	   under reasonable conditions. For an executable file, complete source
- *	   code means the source code for all modules it contains. It does not
- *	   include source code for modules or files that typically accompany the
- *	   major components of the operating system on which the executable file
- *	   runs.
- *	
- *	THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- *	AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- *	IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- *	ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
- *	LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- *	CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- *	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- *	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- *	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- *	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- *	POSSIBILITY OF SUCH DAMAGE.
- */
-
-#define __MAIN_CXX__
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include "common.h"
-
-#include "str.h"
-#include "scriptreader.h"
-#include "objwriter.h"
-#include "events.h"
-#include "commands.h"
-#include "stringtable.h"
-#include "variables.h"
-#include "array.h"
-#include "databuffer.h"
-
-#include "bots.h"
-#include "botcommands.h"
-
-// List of keywords
-const char* g_Keywords[] = {
-	"bool",
-	"break",
-	"case",
-	"continue",
-	"const",
-	"default",
-	"do",
-	"else",
-	"event",
-	"for",
-	"goto",
-	"if",
-	"int",
-	"mainloop",
-	"onenter",
-	"onexit",
-	"state",
-	"switch",
-	"str"
-	"void",
-	"while",
-	
-	// These ones aren't implemented yet but I plan to do so, thus they are
-	// reserved. Also serves as a to-do list of sorts for me. >:F
-	"enum", // Would enum actually be useful? I think so.
-	"func", // Would function support need external support from zandronum?
-	"return",
-};
-
-// databuffer global variable
-int g_NextMark = 0;
-
-int main (int argc, char** argv) {
-	// Intepret command-line parameters:
-	// -l: list commands
-	// I guess there should be a better way to do this.
-	if (argc == 2 && !strcmp (argv[1], "-l")) {
-		ReadCommands ();
-		printf ("Begin list of commands:\n");
-		printf ("------------------------------------------------------\n");
-		
-		CommandDef* comm;
-		ITERATE_COMMANDS (comm)
-			printf ("%s\n", GetCommandPrototype (comm).chars());
-		
-		printf ("------------------------------------------------------\n");
-		printf ("End of command list\n");
-		exit (0);
-	}
-	
-	// Print header
-	str header;
-	str headerline = "-=";
-	header.appendformat ("%s version %d.%d", APPNAME, VERSION_MAJOR, VERSION_MINOR);
-	
-	headerline *= (header.len() / 2) - 1;
-	headerline += '-';
-	printf ("%s\n%s\n", header.chars(), headerline.chars());
-	
-	if (argc < 2) {
-		fprintf (stderr, "usage: %s <infile> [outfile] # compiles botscript\n", argv[0]);
-		fprintf (stderr, "       %s -l                 # lists commands\n", argv[0]);
-		exit (1);
-	}
-	
-	// A word should always be exactly 4 bytes. The above list command
-	// doesn't need it, but the rest of the program does.
-	if (sizeof (word) != 4)
-		error ("%s expects a word (uint32_t) to be 4 bytes in size, is %d\n",
-			APPNAME, sizeof (word));
-	
-	str outfile;
-	if (argc < 3)
-		outfile = ObjectFileName (argv[1]);
-	else
-		outfile = argv[2];
-	
-	// If we'd end up writing into an existing file,
-	// ask the user if we want to overwrite it
-	if (fexists (outfile)) {
-		// Additional warning if the paths are the same
-		str warning;
-#ifdef FILE_CASEINSENSITIVE
-		if (!outfile.icompare (argv[1]))
-#else
-		if (!outfile.compare (argv[1]))
-#endif
-		{
-			warning = "\nWARNING: Output file is the same as the input file. ";
-			warning += "Answering yes here will destroy the source!\n";
-			warning += "Continue nevertheless?";
-		}
-		printf ("output file `%s` already exists! overwrite?%s (y/n) ", outfile.chars(), warning.chars());
-		
-		char ans;
-		fgets (&ans, 2, stdin);
-		if (ans != 'y') {
-			printf ("abort\n");
-			exit (1);
-		}
-	}
-	
-	// Read definitions
-	printf ("Reading definitions...\n");
-	ReadEvents ();
-	ReadCommands ();
-	
-	// Init stuff
-	InitStringTable ();
-	
-	// Prepare reader and writer
-	ScriptReader* r = new ScriptReader (argv[1]);
-	ObjWriter* w = new ObjWriter (outfile);
-	
-	// We're set, begin parsing :)
-	printf ("Parsing script...\n");
-	r->ParseBotScript (w);
-	printf ("Script parsed successfully.\n");
-	
-	// Parse done, print statistics and write to file
-	unsigned int globalcount = g_GlobalVariables.size();
-	unsigned int stringcount = CountStringTable ();
-	int NumMarks = w->MainBuffer->CountMarks ();
-	int NumRefs = w->MainBuffer->CountReferences ();
-	printf ("%u / %u strings written\n", stringcount, MAX_LIST_STRINGS);
-	printf ("%u / %u global variables\n", globalcount, MAX_SCRIPT_VARIABLES);
-	printf ("%d / %d bytecode marks\n", NumMarks, MAX_MARKS);
-	printf ("%d / %d bytecode references\n", NumRefs, MAX_MARKS);
-	printf ("%d / %d events\n", g_NumEvents, MAX_NUM_EVENTS);
-	printf ("%d state%s\n", g_NumStates, PLURAL (g_NumStates));
-	
-	w->WriteToFile ();
-	
-	// Clear out the junk
-	delete r;
-	delete w;
-	
-	// Done!
-	exit (0);
-}
-
-// ============================================================================
-// Utility functions
-
-// ============================================================================
-// Does the given file exist?
-bool fexists (char* path) {
-	if (FILE* test = fopen (path, "r")) {
-		fclose (test);
-		return true;
-	}
-	return false;
-}
-
-// ============================================================================
-// Generic error
-void error (const char* text, ...) {
-	PERFORM_FORMAT (text, c);
-	fprintf (stderr, "error: %s", c);
-	exit (1);
-}
-
-// ============================================================================
-// Mutates given filename to an object filename
-char* ObjectFileName (str s) {
-	// Locate the extension and chop it out
-	unsigned int extdot = s.last (".");
-	if (extdot >= s.len()-4)
-		s -= (s.len() - extdot);
-	
-	s += ".o";
-	return s.chars();
-}
-
-// ============================================================================
-// Is the given argument a reserved keyword?
-bool IsKeyword (str s) {
-	for (unsigned int u = 0; u < NumKeywords (); u++)
-		if (!s.icompare (g_Keywords[u]))
-			return true;
-	return false;
-}
-
-unsigned int NumKeywords () {
-	return sizeof (g_Keywords) / sizeof (const char*);
-}
-
-// ============================================================================
-type_e GetTypeByName (str t) {
-	t = t.tolower();
-	return	(t == "int") ? TYPE_INT :
-			(t == "str") ? TYPE_STRING :
-			(t == "void") ? TYPE_VOID :
-			(t == "bool") ? TYPE_BOOL :
-			TYPE_UNKNOWN;
-}
-
-
-// ============================================================================
-// Inverse operation - type name by value
-str GetTypeName (type_e type) {
-	switch (type) {
-	case TYPE_INT: return "int"; break;
-	case TYPE_STRING: return "str"; break;
-	case TYPE_VOID: return "void"; break;
-	case TYPE_BOOL: return "bool"; break;
-	case TYPE_UNKNOWN: return "???"; break;
-	}
-	
-	return "";
-}
\ No newline at end of file
--- a/objwriter.cxx	Wed Jan 02 23:57:46 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,193 +0,0 @@
-/*
- *	botc source code
- *	Copyright (C) 2012 Santeri `Dusk` Piippo
- *	All rights reserved.
- *	
- *	Redistribution and use in source and binary forms, with or without
- *	modification, are permitted provided that the following conditions are met:
- *	
- *	1. Redistributions of source code must retain the above copyright notice,
- *	   this list of conditions and the following disclaimer.
- *	2. Redistributions in binary form must reproduce the above copyright notice,
- *	   this list of conditions and the following disclaimer in the documentation
- *	   and/or other materials provided with the distribution.
- *	3. Neither the name of the developer nor the names of its contributors may
- *	   be used to endorse or promote products derived from this software without
- *	   specific prior written permission.
- *	4. Redistributions in any form must be accompanied by information on how to
- *	   obtain complete source code for the software and any accompanying
- *	   software that uses the software. The source code must either be included
- *	   in the distribution or be available for no more than the cost of
- *	   distribution plus a nominal fee, and must be freely redistributable
- *	   under reasonable conditions. For an executable file, complete source
- *	   code means the source code for all modules it contains. It does not
- *	   include source code for modules or files that typically accompany the
- *	   major components of the operating system on which the executable file
- *	   runs.
- *	
- *	THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- *	AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- *	IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- *	ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
- *	LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- *	CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- *	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- *	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- *	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- *	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- *	POSSIBILITY OF SUCH DAMAGE.
- */
-
-#define __OBJWRITER_CXX__
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include "common.h"
-#include "str.h"
-#include "objwriter.h"
-#include "databuffer.h"
-#include "stringtable.h"
-
-#include "bots.h"
-
-extern bool g_GotMainLoop;
-
-ObjWriter::ObjWriter (str path) {
-	MainBuffer = new DataBuffer;
-	MainLoopBuffer = new DataBuffer;
-	OnEnterBuffer = new DataBuffer;
-	SwitchBuffer = NULL; // created on demand
-	numWrittenBytes = 0;
-	numWrittenReferences = 0;
-	filepath = path;
-}
-
-void ObjWriter::WriteString (char* s) {
-	Write (strlen (s));
-	for (unsigned int u = 0; u < strlen (s); u++)
-		Write ((s)[u]);
-}
-
-void ObjWriter::WriteString (const char* s) {
-	WriteString (const_cast<char*> (s));
-}
-
-void ObjWriter::WriteString (str s) {
-	WriteString (s.chars());
-}
-
-void ObjWriter::WriteBuffer (DataBuffer* buf) {
-	GetCurrentBuffer()->Merge (buf);
-}
-
-void ObjWriter::WriteBuffers () {
-	// If there was no mainloop defined, write a dummy one now.
-	if (!g_GotMainLoop) {
-		MainLoopBuffer->Write (DH_MAINLOOP);
-		MainLoopBuffer->Write (DH_ENDMAINLOOP);
-	}
-	
-	// Write the onenter and mainloop buffers, IN THAT ORDER
-	for (int i = 0; i < 2; i++) {
-		DataBuffer** buf = (!i) ? &OnEnterBuffer : &MainLoopBuffer;
-		WriteBuffer (*buf);
-		
-		// Clear the buffer afterwards for potential next state
-		*buf = new DataBuffer;
-	}
-	
-	// Next state definitely has no mainloop yet
-	g_GotMainLoop = false;
-}
-
-// Write string table
-void ObjWriter::WriteStringTable () {
-	unsigned int stringcount = CountStringTable ();
-	if (!stringcount)
-		return;
-	
-	// Write header
-	Write (DH_STRINGLIST);
-	Write (stringcount);
-	
-	// Write all strings
-	for (unsigned int a = 0; a < stringcount; a++)
-		WriteString (g_StringTable[a]);
-}
-
-// Write main buffer to file
-void ObjWriter::WriteToFile () {
-	fp = fopen (filepath, "w");
-	CHECK_FILE (fp, filepath, "writing");
-	
-	// First, resolve references
-	numWrittenReferences = 0;
-	for (unsigned int u = 0; u < MAX_MARKS; u++) {
-		ScriptMarkReference* ref = MainBuffer->refs[u];
-		if (!ref)
-			continue;
-		
-		// Substitute the placeholder with the mark position
-		union_t<word> uni;
-		uni.val = static_cast<word> (MainBuffer->marks[ref->num]->pos);
-		for (unsigned int v = 0; v < sizeof (word); v++)
-			memset (MainBuffer->buffer + ref->pos + v, uni.b[v], 1);
-		
-		/*
-		printf ("reference %u at %d resolved to %u at %d\n",
-			u, ref->pos, ref->num, MainBuffer->marks[ref->num]->pos);
-		*/
-		numWrittenReferences++;
-	}
-	
-	// Then, dump the main buffer to the file
-	for (unsigned int x = 0; x < MainBuffer->writesize; x++)
-		WriteDataToFile<byte> (*(MainBuffer->buffer+x));
-	
-	printf ("-- %u byte%s written to %s\n", numWrittenBytes, PLURAL (numWrittenBytes), filepath.chars());
-	fclose (fp);
-}
-
-DataBuffer* ObjWriter::GetCurrentBuffer() {
-	return	SwitchBuffer ? SwitchBuffer :
-		(g_CurMode == MODE_MAINLOOP) ? MainLoopBuffer :
-		(g_CurMode == MODE_ONENTER) ? OnEnterBuffer :
-		MainBuffer;
-}
-
-ScriptMark* g_ScriptMark = NULL;
-
-// Adds a mark
-unsigned int ObjWriter::AddMark (str name) {
-	return GetCurrentBuffer()->AddMark (name);
-}
-
-// Adds a reference
-unsigned int ObjWriter::AddReference (unsigned int mark) {
-	DataBuffer* b = GetCurrentBuffer();
-	return b->AddMarkReference (mark);
-}
-
-// Finds a mark
-unsigned int ObjWriter::FindMark (str name) {
-	DataBuffer* b = GetCurrentBuffer();
-	for (unsigned int u = 0; u < MAX_MARKS; u++) {
-		if (b->marks[u] && !b->marks[u]->name.icompare (name))
-			return u;
-	}
-	return MAX_MARKS;
-}
-
-// Moves a mark to the current position
-void ObjWriter::MoveMark (unsigned int mark) {
-	GetCurrentBuffer()->MoveMark (mark);
-}
-
-// Deletes a mark
-void ObjWriter::DeleteMark (unsigned int mark) {
-	GetCurrentBuffer()->DeleteMark (mark);
-}
-
-void ObjWriter::OffsetMark (unsigned int mark, int offset) {
-	GetCurrentBuffer()->OffsetMark (mark, offset);
-}
\ No newline at end of file
--- a/objwriter.h	Wed Jan 02 23:57:46 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,128 +0,0 @@
-/*
- *	botc source code
- *	Copyright (C) 2012 Santeri `Dusk` Piippo
- *	All rights reserved.
- *	
- *	Redistribution and use in source and binary forms, with or without
- *	modification, are permitted provided that the following conditions are met:
- *	
- *	1. Redistributions of source code must retain the above copyright notice,
- *	   this list of conditions and the following disclaimer.
- *	2. Redistributions in binary form must reproduce the above copyright notice,
- *	   this list of conditions and the following disclaimer in the documentation
- *	   and/or other materials provided with the distribution.
- *	3. Neither the name of the developer nor the names of its contributors may
- *	   be used to endorse or promote products derived from this software without
- *	   specific prior written permission.
- *	4. Redistributions in any form must be accompanied by information on how to
- *	   obtain complete source code for the software and any accompanying
- *	   software that uses the software. The source code must either be included
- *	   in the distribution or be available for no more than the cost of
- *	   distribution plus a nominal fee, and must be freely redistributable
- *	   under reasonable conditions. For an executable file, complete source
- *	   code means the source code for all modules it contains. It does not
- *	   include source code for modules or files that typically accompany the
- *	   major components of the operating system on which the executable file
- *	   runs.
- *	
- *	THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- *	AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- *	IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- *	ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
- *	LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- *	CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- *	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- *	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- *	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- *	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- *	POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef __OBJWRITER_H__
-#define __OBJWRITER_H__
-
-#include <stdio.h>
-#include <typeinfo>
-#include <string.h>
-#include "common.h"
-#include "str.h"
-#include "databuffer.h"
-
-class ObjWriter {
-public:
-	// ====================================================================
-	// MEMBERS
-	
-	// Pointer to the file we're writing to
-	FILE* fp;
-	
-	// Path to the file we're writing to
-	str filepath;
-	
-	// The main buffer - the contents of this is what we
-	// write to file after parsing is complete
-	DataBuffer* MainBuffer;
-	
-	// onenter buffer - the contents of the onenter{} block
-	// is buffered here and is merged further at the end of state
-	DataBuffer* OnEnterBuffer;
-	
-	// Mainloop buffer - the contents of the mainloop{} block
-	// is buffered here and is merged further at the end of state
-	DataBuffer* MainLoopBuffer;
-	
-	// Switch buffer - switch case data is recorded to this
-	// buffer initially, instead of into main buffer.
-	DataBuffer* SwitchBuffer;
-	
-	// How many bytes have we written to file?
-	unsigned int numWrittenBytes;
-	
-	// How many references did we resolve in the main buffer?
-	unsigned int numWrittenReferences;
-	
-	// ====================================================================
-	// METHODS
-	ObjWriter (str path);
-	void WriteString (char* s);
-	void WriteString (const char* s);
-	void WriteString (str s);
-	void WriteBuffer (DataBuffer* buf);
-	void WriteBuffers ();
-	void WriteStringTable ();
-	void WriteToFile ();
-	DataBuffer* GetCurrentBuffer ();
-	
-	unsigned int AddMark (str name);
-	unsigned int FindMark (str name);
-	unsigned int AddReference (unsigned int mark);
-	void MoveMark (unsigned int mark);
-	void OffsetMark (unsigned int mark, int offset);
-	void DeleteMark (unsigned int mark);
-	template <class T> void DoWrite (const char* func, T stuff) {
-		GetCurrentBuffer ()->DoWrite (func, stuff);
-	}
-	
-	// Default to word
-	void DoWrite (const char* func, word stuff) {
-		DoWrite<word> (func, stuff);
-	}
-	
-	void DoWrite (const char* func, byte stuff) {
-		DoWrite<byte> (func, stuff);
-	}
-	
-private:
-	// Write given data to file.
-	template <class T> void WriteDataToFile (T stuff) {
-		// One byte at a time
-		union_t<T> uni;
-		uni.val = stuff;
-		for (unsigned int x = 0; x < sizeof (T); x++) {
-			fwrite (&uni.b[x], 1, 1, fp);
-			numWrittenBytes++;
-		}
-	}
-};
-
-#endif // __OBJWRITER_H__
\ No newline at end of file
--- a/parser.cxx	Wed Jan 02 23:57:46 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1203 +0,0 @@
-/*
- *	botc source code
- *	Copyright (C) 2012 Santeri `Dusk` Piippo
- *	All rights reserved.
- *	
- *	Redistribution and use in source and binary forms, with or without
- *	modification, are permitted provided that the following conditions are met:
- *	
- *	1. Redistributions of source code must retain the above copyright notice,
- *	   this list of conditions and the following disclaimer.
- *	2. Redistributions in binary form must reproduce the above copyright notice,
- *	   this list of conditions and the following disclaimer in the documentation
- *	   and/or other materials provided with the distribution.
- *	3. Neither the name of the developer nor the names of its contributors may
- *	   be used to endorse or promote products derived from this software without
- *	   specific prior written permission.
- *	4. Redistributions in any form must be accompanied by information on how to
- *	   obtain complete source code for the software and any accompanying
- *	   software that uses the software. The source code must either be included
- *	   in the distribution or be available for no more than the cost of
- *	   distribution plus a nominal fee, and must be freely redistributable
- *	   under reasonable conditions. For an executable file, complete source
- *	   code means the source code for all modules it contains. It does not
- *	   include source code for modules or files that typically accompany the
- *	   major components of the operating system on which the executable file
- *	   runs.
- *	
- *	THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- *	AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- *	IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- *	ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
- *	LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- *	CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- *	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- *	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- *	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- *	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- *	POSSIBILITY OF SUCH DAMAGE.
- */
-
-#define __PARSER_CXX__
-
-#include <stdio.h>
-#include <stdlib.h>
-#include "common.h"
-#include "str.h"
-#include "objwriter.h"
-#include "scriptreader.h"
-#include "events.h"
-#include "commands.h"
-#include "stringtable.h"
-#include "variables.h"
-#include "array.h"
-
-#define MUST_TOPLEVEL if (g_CurMode != MODE_TOPLEVEL) \
-	ParserError ("%s-statements may only be defined at top level!", token.chars());
-
-#define MUST_NOT_TOPLEVEL if (g_CurMode == MODE_TOPLEVEL) \
-	ParserError ("%s-statements may not be defined at top level!", token.chars());
-
-#define SCOPE(n) scopestack[g_ScopeCursor - n]
-
-int g_NumStates = 0;
-int g_NumEvents = 0;
-parsermode_e g_CurMode = MODE_TOPLEVEL;
-str g_CurState = "";
-bool g_stateSpawnDefined = false;
-bool g_GotMainLoop = false;
-unsigned int g_ScopeCursor = 0;
-DataBuffer* g_IfExpression = NULL;
-bool g_CanElse = false;
-str* g_UndefinedLabels[MAX_MARKS];
-bool g_Neurosphere = false; // neurosphere-compat
-array<constinfo_t> g_ConstInfo;
-
-// ============================================================================
-// Main parser code. Begins read of the script file, checks the syntax of it
-// and writes the data to the object file via ObjWriter - which also takes care
-// of necessary buffering so stuff is written in the correct order.
-void ScriptReader::ParseBotScript (ObjWriter* w) {
-	// Zero the entire block stack first
-	for (int i = 0; i < MAX_SCOPE; i++)
-		ZERO(scopestack[i]);
-	
-	for (int i = 0; i < MAX_MARKS; i++)
-		g_UndefinedLabels[i] = NULL;
-	
-	while (Next()) {
-		// Check if else is potentically valid
-		if (token == "else" && !g_CanElse)
-			ParserError ("else without preceding if");
-		if (token != "else")
-			g_CanElse = false;
-		
-		// ============================================================
-		if (token == "state") {
-			MUST_TOPLEVEL
-			
-			MustString ();
-			
-			// State name must be a word.
-			if (token.first (" ") != token.len())
-				ParserError ("state name must be a single word, got `%s`", token.chars());
-			str statename = token;
-			
-			// stateSpawn is special - it *must* be defined. If we
-			// encountered it, then mark down that we have it.
-			if (-token == "statespawn")
-				g_stateSpawnDefined = true;
-			
-			// Must end in a colon
-			MustNext (":");
-			
-			// Write the previous state's onenter and
-			// mainloop buffers to file now
-			if (g_CurState.len())
-				w->WriteBuffers();
-			
-			w->Write (DH_STATENAME);
-			w->WriteString (statename);
-			w->Write (DH_STATEIDX);
-			w->Write (g_NumStates);
-			
-			g_NumStates++;
-			g_CurState = token;
-			g_GotMainLoop = false;
-			continue;
-		}
-		
-		// ============================================================
-		if (token == "event") {
-			MUST_TOPLEVEL
-			
-			// Event definition
-			MustString ();
-			
-			EventDef* e = FindEventByName (token);
-			if (!e)
-				ParserError ("bad event, got `%s`\n", token.chars());
-			
-			MustNext ("{");
-			
-			g_CurMode = MODE_EVENT;
-			
-			w->Write (DH_EVENT);
-			w->Write (e->number);
-			g_NumEvents++;
-			continue;
-		}
-		
-		// ============================================================
-		if (token == "mainloop") {
-			MUST_TOPLEVEL
-			MustNext ("{");
-			
-			// Mode must be set before dataheader is written here!
-			g_CurMode = MODE_MAINLOOP;
-			w->Write (DH_MAINLOOP);
-			continue;
-		}
-		
-		// ============================================================
-		if (token == "onenter" || token == "onexit") {
-			MUST_TOPLEVEL
-			bool onenter = token == "onenter";
-			MustNext ("{");
-			
-			// Mode must be set before dataheader is written here,
-			// because onenter goes to a separate buffer.
-			g_CurMode = onenter ? MODE_ONENTER : MODE_ONEXIT;
-			w->Write (onenter ? DH_ONENTER : DH_ONEXIT);
-			continue;
-		}
-		
-		// ============================================================
-		if (token == "int" || token == "str" || token == "bool") {
-			// For now, only globals are supported
-			if (g_CurMode != MODE_TOPLEVEL || g_CurState.len())
-				ParserError ("variables must only be global for now");
-			
-			type_e type =	(token == "int") ? TYPE_INT :
-							(token == "str") ? TYPE_STRING :
-							TYPE_BOOL;
-			
-			MustNext ();
-			
-			// Var name must not be a number
-			if (token.isnumber())
-				ParserError ("variable name must not be a number");
-			
-			str varname = token;
-			ScriptVar* var = DeclareGlobalVariable (this, type, varname);
-			
-			if (!var)
-				ParserError ("declaring %s variable %s failed",
-					g_CurState.len() ? "state" : "global", varname.chars());
-			
-			MustNext (";");
-			continue;
-		}
-		
-		// ============================================================
-		// Goto
-		if (token == "goto") {
-			MUST_NOT_TOPLEVEL
-			
-			// Get the name of the label
-			MustNext ();
-			
-			// Find the mark this goto statement points to
-			unsigned int m = w->FindMark (token);
-			
-			// If not set, define it
-			if (m == MAX_MARKS) {
-				m = w->AddMark (token);
-				g_UndefinedLabels[m] = new str (token);
-			}
-			
-			// Add a reference to the mark.
-			w->Write (DH_GOTO);
-			w->AddReference (m);
-			MustNext (";");
-			continue;
-		}
-		
-		// ============================================================
-		// If
-		if (token == "if") {
-			MUST_NOT_TOPLEVEL
-			PushScope ();
-			
-			// Condition
-			MustNext ("(");
-			
-			// Read the expression and write it.
-			MustNext ();
-			DataBuffer* c = ParseExpression (TYPE_INT);
-			w->WriteBuffer (c);
-			
-			MustNext (")");
-			MustNext ("{");
-			
-			// Add a mark - to here temporarily - and add a reference to it.
-			// Upon a closing brace, the mark will be adjusted.
-			unsigned int marknum = w->AddMark ("");
-			
-			// Use DH_IFNOTGOTO - if the expression is not true, we goto the mark
-			// we just defined - and this mark will be at the end of the scope block.
-			w->Write (DH_IFNOTGOTO);
-			w->AddReference (marknum);
-			
-			// Store it
-			SCOPE(0).mark1 = marknum;
-			SCOPE(0).type = SCOPETYPE_IF;
-			continue;
-		}
-		
-		if (token == "else") {
-			MUST_NOT_TOPLEVEL
-			MustNext ("{");
-			
-			// Don't use PushScope as it resets the scope
-			g_ScopeCursor++;
-			if (g_ScopeCursor >= MAX_SCOPE)
-				ParserError ("too deep scope");
-			
-			if (SCOPE(0).type != SCOPETYPE_IF)
-				ParserError ("else without preceding if");
-			
-			// Write down to jump to the end of the else statement
-			// Otherwise we have fall-throughs
-			SCOPE(0).mark2 = w->AddMark ("");
-			
-			// Instruction to jump to the end after if block is complete
-			w->Write (DH_GOTO);
-			w->AddReference (SCOPE(0).mark2);
-			
-			// Move the ifnot mark here and set type to else
-			w->MoveMark (SCOPE(0).mark1);
-			SCOPE(0).type = SCOPETYPE_ELSE;
-			continue;
-		}
-		
-		// ============================================================
-		// While
-		if (token == "while") {
-			MUST_NOT_TOPLEVEL
-			PushScope ();
-			
-			// While loops need two marks - one at the start of the loop and one at the
-			// end. The condition is checked at the very start of the loop, if it fails,
-			// we use goto to skip to the end of the loop. At the end, we loop back to
-			// the beginning with a go-to statement.
-			unsigned int mark1 = w->AddMark (""); // start
-			unsigned int mark2 = w->AddMark (""); // end
-			
-			// Condition
-			MustNext ("(");
-			MustNext ();
-			DataBuffer* expr = ParseExpression (TYPE_INT);
-			MustNext (")");
-			MustNext ("{");
-			
-			// Write condition
-			w->WriteBuffer (expr);
-			
-			// Instruction to go to the end if it fails
-			w->Write (DH_IFNOTGOTO);
-			w->AddReference (mark2);
-			
-			// Store the needed stuff
-			SCOPE(0).mark1 = mark1;
-			SCOPE(0).mark2 = mark2;
-			SCOPE(0).type = SCOPETYPE_WHILE;
-			continue;
-		}
-		
-		// ============================================================
-		// For loop
-		if (token == "for") {
-			MUST_NOT_TOPLEVEL
-			PushScope ();
-			
-			// Initializer
-			MustNext ("(");
-			MustNext ();
-			DataBuffer* init = ParseStatement (w);
-			if (!init)
-				ParserError ("bad statement for initializer of for");
-			
-			MustNext (";");
-			
-			// Condition
-			MustNext ();
-			DataBuffer* cond = ParseExpression (TYPE_INT);
-			if (!cond)
-				ParserError ("bad statement for condition of for");
-			
-			MustNext (";");
-			
-			// Incrementor
-			MustNext ();
-			DataBuffer* incr = ParseStatement (w);
-			if (!incr)
-				ParserError ("bad statement for incrementor of for");
-			
-			MustNext (")");
-			MustNext ("{");
-			
-			// First, write out the initializer
-			w->WriteBuffer (init);
-			
-			// Init two marks
-			int mark1 = w->AddMark ("");
-			int mark2 = w->AddMark ("");
-			
-			// Add the condition
-			w->WriteBuffer (cond);
-			w->Write (DH_IFNOTGOTO);
-			w->AddReference (mark2);
-			
-			// Store the marks and incrementor
-			SCOPE(0).mark1 = mark1;
-			SCOPE(0).mark2 = mark2;
-			SCOPE(0).buffer1 = incr;
-			SCOPE(0).type = SCOPETYPE_FOR;
-			continue;
-		}
-		
-		// ============================================================
-		// Do/while loop
-		if (token == "do") {
-			MUST_NOT_TOPLEVEL
-			PushScope ();
-			MustNext ("{");
-			SCOPE(0).mark1 = w->AddMark ("");
-			SCOPE(0).type = SCOPETYPE_DO;
-			continue;
-		}
-		
-		// ============================================================
-		// Switch
-		if (token == "switch") {
-			/* This goes a bit tricky. switch is structured in the
-			 * bytecode followingly:
-			 * (expression)
-			 * case a: goto casemark1
-			 * case b: goto casemark2
-			 * case c: goto casemark3
-			 * goto mark1 // jump to end if no matches
-			 * casemark1: ...
-			 * casemark2: ...
-			 * casemark3: ...
-			 * mark1: // end mark
-			 */
-			
-			MUST_NOT_TOPLEVEL
-			PushScope ();
-			MustNext ("(");
-			MustNext ();
-			w->WriteBuffer (ParseExpression (TYPE_INT));
-			MustNext (")");
-			MustNext ("{");
-			SCOPE(0).type = SCOPETYPE_SWITCH;
-			SCOPE(0).mark1 = w->AddMark (""); // end mark
-			SCOPE(0).buffer1 = NULL; // default header
-			continue;
-		}
-		
-		// ============================================================
-		if (token == "case") {
-			// case is only allowed inside switch
-			if (SCOPE(0).type != SCOPETYPE_SWITCH)
-				ParserError ("case label outside switch");
-			
-			// Get the literal (Zandronum does not support expressions here)
-			MustNumber ();
-			int num = atoi (token.chars ());
-			MustNext (":");
-			
-			for (int i = 0; i < MAX_CASE; i++)
-				if (SCOPE(0).casenumbers[i] == num)
-					ParserError ("multiple case %d labels in one switch", num);
-			
-			// Write down the expression and case-go-to. This builds
-			// the case tree. The closing event will write the actual
-			// blocks and move the marks appropriately.
-			//	AddSwitchCase will add the reference to the mark
-			// for the case block that this heralds, and takes care
-			// of buffering setup and stuff like that.
-			//	NULL the switch buffer for the case-go-to statement,
-			// we want it all under the switch, not into the case-buffers.
-			w->SwitchBuffer = NULL;
-			w->Write (DH_CASEGOTO);
-			w->Write (num);
-			AddSwitchCase (w, NULL);
-			SCOPE(0).casenumbers[SCOPE(0).casecursor] = num;
-			continue;
-		}
-		
-		if (token == "default") {
-			if (SCOPE(0).type != SCOPETYPE_SWITCH)
-				ParserError ("default label outside switch");
-			
-			if (SCOPE(0).buffer1)
-				ParserError ("multiple default labels in one switch");
-			
-			MustNext (":");
-			
-			// The default header is buffered into buffer1, since
-			// it has to be the last of the case headers
-			//
-			// Since the expression is pushed into the switch
-			// and is only popped when case succeeds, we have
-			// to pop it with DH_DROP manually if we end up in
-			// a default.
-			DataBuffer* b = new DataBuffer;
-			SCOPE(0).buffer1 = b;
-			b->Write (DH_DROP);
-			b->Write (DH_GOTO);
-			AddSwitchCase (w, b);
-			continue;
-		}
-		
-		// ============================================================
-		// Break statement.
-		if (token == "break") {
-			if (!g_ScopeCursor)
-				ParserError ("unexpected `break`");
-			
-			w->Write (DH_GOTO);
-			
-			// switch and if use mark1 for the closing point,
-			// for and while use mark2.
-			switch (SCOPE(0).type) {
-			case SCOPETYPE_IF:
-			case SCOPETYPE_SWITCH:
-				w->AddReference (SCOPE(0).mark1);
-				break;
-			case SCOPETYPE_FOR:
-			case SCOPETYPE_WHILE:
-				w->AddReference (SCOPE(0).mark2);
-				break;
-			default:
-				ParserError ("unexpected `break`");
-				break;
-			}
-			
-			MustNext (";");
-			continue;
-		}
-		
-		// ============================================================
-		// Continue
-		if (token == "continue") {
-			MustNext (";");
-			
-			int curs;
-			bool found = false;
-			
-			// Drop through the scope until we find a loop block
-			for (curs = g_ScopeCursor; curs > 0 && !found; curs--) {
-				switch (scopestack[curs].type) {
-				case SCOPETYPE_FOR:
-				case SCOPETYPE_WHILE:
-				case SCOPETYPE_DO:
-					w->Write (DH_GOTO);
-					w->AddReference (scopestack[curs].mark1);
-					found = true;
-					break;
-				default:
-					break;
-				}
-			}
-			
-			// No loop blocks
-			if (!found)
-				ParserError ("`continue`-statement not inside a loop");
-			
-			continue;
-		}
-		
-		// ============================================================
-		// Label
-		if (PeekNext() == ":") {
-			MUST_NOT_TOPLEVEL
-			
-			// want no conflicts..
-			if (IsKeyword (token))
-				ParserError ("label name `%s` conflicts with keyword\n", token.chars());
-			if (FindCommand (token))
-				ParserError ("label name `%s` conflicts with command name\n", token.chars());
-			if (FindGlobalVariable (token))
-				ParserError ("label name `%s` conflicts with variable\n", token.chars());
-			
-			// See if a mark already exists for this label
-			int mark = -1;
-			for (int i = 0; i < MAX_MARKS; i++) {
-				if (g_UndefinedLabels[i] && *g_UndefinedLabels[i] == token) {
-					mark = i;
-					w->MoveMark (i);
-					
-					// No longer undefinde
-					delete g_UndefinedLabels[i];
-					g_UndefinedLabels[i] = NULL;
-				}
-			}
-			
-			// Not found in unmarked lists, define it now
-			if (mark == -1)
-				w->AddMark (token);
-			
-			MustNext (":");
-			continue;
-		}
-		
-		// ============================================================
-		if (token == "const") {
-			constinfo_t info;
-			
-			// Get the type
-			MustNext ();
-			info.type = GetTypeByName (token);
-			
-			if (info.type == TYPE_UNKNOWN || info.type == TYPE_VOID)
-				ParserError ("unknown type `%s` for constant", (char*)token);
-			
-			MustNext ();
-			info.name = token;
-			
-			MustNext ("=");
-			
-			switch (info.type) {
-			case TYPE_BOOL:
-			case TYPE_INT:
-				MustNumber (false);
-				info.val = token;
-				break;
-			case TYPE_STRING:
-				MustString ();
-				info.val = token;
-				break;
-			case TYPE_UNKNOWN:
-			case TYPE_VOID:
-				break;
-			}
-			
-			g_ConstInfo << info;
-			
-			MustNext (";");
-			continue;
-		}
-		
-		// ============================================================
-		if (token == "}") {
-			// Closing brace
-			
-			// If we're in the block stack, we're descending down from it now
-			if (g_ScopeCursor > 0) {
-				switch (SCOPE(0).type) {
-				case SCOPETYPE_IF:
-					// Adjust the closing mark.
-					w->MoveMark (SCOPE(0).mark1);
-					
-					// We're returning from if, thus else can be next
-					g_CanElse = true;
-					break;
-				case SCOPETYPE_ELSE:
-					// else instead uses mark1 for itself (so if expression
-					// fails, jump to else), mark2 means end of else
-					w->MoveMark (SCOPE(0).mark2);
-					break;
-				case SCOPETYPE_FOR:
-					// Write the incrementor at the end of the loop block
-					w->WriteBuffer (SCOPE(0).buffer1);
-					// fall-thru
-				case SCOPETYPE_WHILE:
-					// Write down the instruction to go back to the start of the loop
-					w->Write (DH_GOTO);
-					w->AddReference (SCOPE(0).mark1);
-					
-					// Move the closing mark here since we're at the end of the while loop
-					w->MoveMark (SCOPE(0).mark2);
-					break;
-				case SCOPETYPE_DO: { 
-					MustNext ("while");
-					MustNext ("(");
-					MustNext ();
-					DataBuffer* expr = ParseExpression (TYPE_INT);
-					MustNext (")");
-					MustNext (";");
-					
-					// If the condition runs true, go back to the start.
-					w->WriteBuffer (expr);
-					w->Write (DH_IFGOTO);
-					w->AddReference (SCOPE(0).mark1);
-					break;
-				}
-				case SCOPETYPE_SWITCH: {
-					// Switch closes. Move down to the record buffer of
-					// the lower block.
-					if (SCOPE(1).casecursor != -1)
-						w->SwitchBuffer = SCOPE(1).casebuffers[SCOPE(1).casecursor];
-					else
-						w->SwitchBuffer = NULL;
-					
-					// If there was a default in the switch, write its header down now.
-					// If not, write instruction to jump to the end of switch after
-					// the headers (thus won't fall-through if no case matched)
-					if (SCOPE(0).buffer1)
-						w->WriteBuffer (SCOPE(0).buffer1);
-					else {
-						w->Write (DH_DROP);
-						w->Write (DH_GOTO);
-						w->AddReference (SCOPE(0).mark1);
-					}
-					
-					// Go through all of the buffers we
-					// recorded down and write them.
-					for (unsigned int u = 0; u < MAX_CASE; u++) {
-						if (!SCOPE(0).casebuffers[u])
-							continue;
-						
-						w->MoveMark (SCOPE(0).casemarks[u]);
-						w->WriteBuffer (SCOPE(0).casebuffers[u]);
-					}
-					
-					// Move the closing mark here
-					w->MoveMark (SCOPE(0).mark1);
-					break;
-				}
-				case SCOPETYPE_UNKNOWN:
-					break;
-				}
-				
-				// Descend down the stack
-				g_ScopeCursor--;
-				continue;
-			}
-			
-			int dataheader =	(g_CurMode == MODE_EVENT) ? DH_ENDEVENT :
-						(g_CurMode == MODE_MAINLOOP) ? DH_ENDMAINLOOP :
-						(g_CurMode == MODE_ONENTER) ? DH_ENDONENTER :
-						(g_CurMode == MODE_ONEXIT) ? DH_ENDONEXIT : -1;
-			
-			if (dataheader == -1)
-				ParserError ("unexpected `}`");
-			
-			// Data header must be written before mode is changed because
-			// onenter and mainloop go into special buffers, and we want
-			// the closing data headers into said buffers too.
-			w->Write (dataheader);
-			g_CurMode = MODE_TOPLEVEL;
-			
-			if (PeekNext() == ";")
-				MustNext (";");
-			continue;
-		}
-		
-		// Check if it's a command
-		CommandDef* comm = FindCommand (token);
-		if (comm) {
-			w->GetCurrentBuffer()->Merge (ParseCommand (comm));
-			MustNext (";");
-			continue;
-		}
-		
-		// ============================================================
-		// If nothing else, parse it as a statement
-		DataBuffer* b = ParseStatement (w);
-		if (!b)
-			ParserError ("unknown token `%s`", token.chars());
-		
-		w->WriteBuffer (b);
-		MustNext (";");
-	}
-	
-	// ===============================================================================
-	// Script file ended. Do some last checks and write the last things to main buffer
-	if (g_CurMode != MODE_TOPLEVEL)
-		ParserError ("script did not end at top level; did you forget a `}`?");
-	
-	// stateSpawn must be defined!
-	if (!g_stateSpawnDefined)
-		ParserError ("script must have a state named `stateSpawn`!");
-	
-	for (int i = 0; i < MAX_MARKS; i++)
-		if (g_UndefinedLabels[i])
-			ParserError ("label `%s` is referenced via `goto` but isn't defined\n", g_UndefinedLabels[i]->chars());
-	
-	// Dump the last state's onenter and mainloop
-	w->WriteBuffers ();
-	
-	// String table
-	w->WriteStringTable ();
-}
-
-// ============================================================================
-// Parses a command call
-DataBuffer* ScriptReader::ParseCommand (CommandDef* comm) {
-	DataBuffer* r = new DataBuffer(64);
-	if (g_CurMode == MODE_TOPLEVEL)
-		ParserError ("command call at top level");
-	
-	MustNext ("(");
-	MustNext ();
-	
-	int curarg = 0;
-	while (1) {
-		if (token == ")") {
-			if (curarg < comm->numargs)
-				ParserError ("too few arguments passed to %s\n\tprototype: %s",
-					comm->name.chars(), GetCommandPrototype (comm).chars());
-			break;
-			curarg++;
-		}
-		
-		if (curarg >= comm->maxargs)
-			ParserError ("too many arguments passed to %s\n\tprototype: %s",
-				comm->name.chars(), GetCommandPrototype (comm).chars());
-		
-		r->Merge (ParseExpression (comm->argtypes[curarg]));
-		MustNext ();
-		
-		if (curarg < comm->numargs - 1) {
-			MustThis (",");
-			MustNext ();
-		} else if (curarg < comm->maxargs - 1) {
-			// Can continue, but can terminate as well.
-			if (token == ")") {
-				curarg++;
-				break;
-			} else {
-				MustThis (",");
-				MustNext ();
-			}
-		}
-		
-		curarg++;
-	}
-	
-	// If the script skipped any optional arguments, fill in defaults.
-	while (curarg < comm->maxargs) {
-		r->Write (DH_PUSHNUMBER);
-		r->Write (comm->defvals[curarg]);
-		curarg++;
-	}
-	
-	r->Write (DH_COMMAND);
-	r->Write (comm->number);
-	r->Write (comm->maxargs);
-	
-	return r;
-}
-
-// ============================================================================
-// Is the given operator an assignment operator?
-static bool IsAssignmentOperator (int oper) {
-	switch (oper) {
-	case OPER_ASSIGNADD:
-	case OPER_ASSIGNSUB:
-	case OPER_ASSIGNMUL:
-	case OPER_ASSIGNDIV:
-	case OPER_ASSIGNMOD:
-	case OPER_ASSIGNLEFTSHIFT:
-	case OPER_ASSIGNRIGHTSHIFT:
-	case OPER_ASSIGN:
-		return true;
-	}
-	return false;
-}
-
-// ============================================================================
-// Finds an operator's corresponding dataheader
-static word DataHeaderByOperator (ScriptVar* var, int oper) {
-	if (IsAssignmentOperator (oper)) {
-		if (!var)
-			error ("operator %d requires left operand to be a variable\n", oper);
-		
-		// TODO: At the moment, vars only are global
-		// OPER_ASSIGNLEFTSHIFT and OPER_ASSIGNRIGHTSHIFT do not
-		// have data headers, instead they are expanded out in
-		// the operator parser
-		switch (oper) {
-		case OPER_ASSIGNADD: return DH_ADDGLOBALVAR;
-		case OPER_ASSIGNSUB: return DH_SUBGLOBALVAR;
-		case OPER_ASSIGNMUL: return DH_MULGLOBALVAR;
-		case OPER_ASSIGNDIV: return DH_DIVGLOBALVAR;
-		case OPER_ASSIGNMOD: return DH_MODGLOBALVAR;
-		case OPER_ASSIGN: return DH_ASSIGNGLOBALVAR;
-		default: error ("bad assignment operator!!\n");
-		}
-	}
-	
-	switch (oper) {
-	case OPER_ADD: return DH_ADD;
-	case OPER_SUBTRACT: return DH_SUBTRACT;
-	case OPER_MULTIPLY: return DH_MULTIPLY;
-	case OPER_DIVIDE: return DH_DIVIDE;
-	case OPER_MODULUS: return DH_MODULUS;
-	case OPER_EQUALS: return DH_EQUALS;
-	case OPER_NOTEQUALS: return DH_NOTEQUALS;
-	case OPER_LESSTHAN: return DH_LESSTHAN;
-	case OPER_GREATERTHAN: return DH_GREATERTHAN;
-	case OPER_LESSTHANEQUALS: return DH_LESSTHANEQUALS;
-	case OPER_GREATERTHANEQUALS: return DH_GREATERTHANEQUALS;
-	case OPER_LEFTSHIFT: return DH_LSHIFT;
-	case OPER_RIGHTSHIFT: return DH_RSHIFT;
-	case OPER_OR: return DH_ORLOGICAL;
-	case OPER_AND: return DH_ANDLOGICAL;
-	case OPER_BITWISEOR: return DH_ORBITWISE;
-	case OPER_BITWISEEOR: return DH_EORBITWISE;
-	case OPER_BITWISEAND: return DH_ANDBITWISE;
-	}
-	
-	error ("DataHeaderByOperator: couldn't find dataheader for operator %d!\n", oper);
-	return 0;
-}
-
-// ============================================================================
-// Parses an expression, potentially recursively
-DataBuffer* ScriptReader::ParseExpression (type_e reqtype) {
-	DataBuffer* retbuf = new DataBuffer (64);
-	
-	// Parse first operand
-	retbuf->Merge (ParseExprValue (reqtype));
-	
-	// Parse any and all operators we get
-	int oper;
-	while ((oper = ParseOperator (true)) != -1) {
-		// We peeked the operator, move forward now
-		Next ();
-		
-		// Can't be an assignement operator, those belong in assignments.
-		if (IsAssignmentOperator (oper))
-			ParserError ("assignment operator inside expression");
-		
-		// Parse the right operand.
-		MustNext ();
-		DataBuffer* rb = ParseExprValue (reqtype);
-		
-		if (oper == OPER_TERNARY) {
-			// Ternary operator requires - naturally - a third operand.
-			MustNext (":");
-			MustNext ();
-			DataBuffer* tb = ParseExprValue (reqtype);
-			
-			// It also is handled differently: there isn't a dataheader for ternary
-			// operator. Instead, we abuse PUSHNUMBER and IFNOTGOTO for this.
-			// Behold, big block of writing madness! :P
-			int mark1 = retbuf->AddMark (""); // start of "else" case
-			int mark2 = retbuf->AddMark (""); // end of expression
-			retbuf->Write (DH_IFNOTGOTO); // if the first operand (condition)
-			retbuf->AddMarkReference (mark1); // didn't eval true, jump into mark1
-			retbuf->Merge (rb); // otherwise, perform second operand (true case)
-			retbuf->Write (DH_GOTO); // afterwards, jump to the end, which is
-			retbuf->AddMarkReference (mark2); // marked by mark2.
-			retbuf->MoveMark (mark1); // move mark1 at the end of the true case
-			retbuf->Merge (tb); // perform third operand (false case)
-			retbuf->MoveMark (mark2); // move the ending mark2 here
-		} else {
-			// Write to buffer
-			retbuf->Merge (rb);
-			retbuf->Write (DataHeaderByOperator (NULL, oper));
-		}
-	}
-	
-	return retbuf;
-}
-
-// ============================================================================
-// Parses an operator string. Returns the operator number code.
-#define ISNEXT(char) (!PeekNext (peek ? 1 : 0) == char)
-int ScriptReader::ParseOperator (bool peek) {
-	str oper;
-	if (peek)
-		oper += PeekNext ();
-	else
-		oper += token;
-	
-	if (-oper == "strlen")
-		return OPER_STRLEN;
-	
-	// Check one-char operators
-	bool equalsnext = ISNEXT ("=");
-	
-	int o =	(oper == "=" && !equalsnext) ? OPER_ASSIGN :
-		(oper == ">" && !equalsnext && !ISNEXT (">")) ? OPER_GREATERTHAN :
-		(oper == "<" && !equalsnext && !ISNEXT ("<")) ? OPER_LESSTHAN :
-		(oper == "&" && !ISNEXT ("&")) ? OPER_BITWISEAND :
-		(oper == "|" && !ISNEXT ("|")) ? OPER_BITWISEOR :
-		(oper == "+" && !equalsnext) ? OPER_ADD :
-		(oper == "-" && !equalsnext) ? OPER_SUBTRACT :
-		(oper == "*" && !equalsnext) ? OPER_MULTIPLY :
-		(oper == "/" && !equalsnext) ? OPER_DIVIDE :
-		(oper == "%" && !equalsnext) ? OPER_MODULUS :
-		(oper == "^") ? OPER_BITWISEEOR :
-		(oper == "?") ? OPER_TERNARY :
-		-1;
-	
-	if (o != -1) {
-		return o;
-	}
-	
-	// Two-char operators
-	oper += PeekNext (peek ? 1 : 0);
-	equalsnext = PeekNext (peek ? 2 : 1) == ("=");
-	
-	o =	(oper == "+=") ? OPER_ASSIGNADD :
-		(oper == "-=") ? OPER_ASSIGNSUB :
-		(oper == "*=") ? OPER_ASSIGNMUL :
-		(oper == "/=") ? OPER_ASSIGNDIV :
-		(oper == "%=") ? OPER_ASSIGNMOD :
-		(oper == "==") ? OPER_EQUALS :
-		(oper == "!=") ? OPER_NOTEQUALS :
-		(oper == ">=") ? OPER_GREATERTHANEQUALS :
-		(oper == "<=") ? OPER_LESSTHANEQUALS :
-		(oper == "&&") ? OPER_AND :
-		(oper == "||") ? OPER_OR :
-		(oper == "<<" && !equalsnext) ? OPER_LEFTSHIFT :
-		(oper == ">>" && !equalsnext) ? OPER_RIGHTSHIFT :
-		-1;
-	
-	if (o != -1) {
-		MustNext ();
-		return o;
-	}
-	
-	// Three-char opers
-	oper += PeekNext (peek ? 2 : 1);
-	o =	oper == "<<=" ? OPER_ASSIGNLEFTSHIFT :
-		oper == ">>=" ? OPER_ASSIGNRIGHTSHIFT :
-		-1;
-	
-	if (o != -1) {
-		MustNext ();
-		MustNext ();
-	}
-	
-	return o;
-}
-
-// ============================================================================
-str ScriptReader::ParseFloat () {
-	MustNumber (true);
-	str floatstring = token;
-	
-	// Go after the decimal point
-	if (PeekNext () == ".") {
-		Next (".");
-		MustNumber (false);
-		floatstring += ".";
-		floatstring += token;
-	}
-	
-	return floatstring;
-}
-
-// ============================================================================
-// Parses a value in the expression and returns the data needed to push
-// it, contained in a data buffer. A value can be either a variable, a command,
-// a literal or an expression.
-DataBuffer* ScriptReader::ParseExprValue (type_e reqtype) {
-	DataBuffer* b = new DataBuffer(16);
-	
-	ScriptVar* g;
-	
-	// Prefixing "!" means negation.
-	bool negate = (token == "!");
-	if (negate) // Jump past the "!"
-		Next ();
-	
-	// Handle strlen
-	if (token == "strlen") {
-		MustNext ("(");
-		MustNext ();
-		
-		// By this token we should get a string constant.
-		constinfo_t* constant = FindConstant (token);
-		if (!constant || constant->type != TYPE_STRING)
-			ParserError ("strlen only works with const str");
-		
-		if (reqtype != TYPE_INT)
-			ParserError ("strlen returns int but %s is expected\n", (char*)GetTypeName (reqtype));
-		
-		b->Write (DH_PUSHNUMBER);
-		b->Write (constant->val.len ());
-		
-		MustNext (")");
-	} else if (token == "(") {
-		// Expression
-		MustNext ();
-		DataBuffer* c = ParseExpression (reqtype);
-		b->Merge (c);
-		MustNext (")");
-	} else if (CommandDef* comm = FindCommand (token)) {
-		delete b;
-		
-		// Command
-		if (reqtype && comm->returnvalue != reqtype)
-			ParserError ("%s returns an incompatible data type", comm->name.chars());
-		b = ParseCommand (comm);
-	} else if (constinfo_t* constant = FindConstant (token)) {
-		// Type check
-		if (reqtype != constant->type)
-			ParserError ("constant `%s` is %s, expression requires %s\n",
-				(char*)constant->name, (char*)GetTypeName (constant->type),
-				(char*)GetTypeName (reqtype));
-		
-		switch (constant->type) {
-		case TYPE_BOOL:
-		case TYPE_INT:
-			b->Write (DH_PUSHNUMBER);
-			b->Write (atoi (constant->val));
-			break;
-		case TYPE_STRING:
-			b->WriteString (constant->val);
-			break;
-		case TYPE_VOID:
-		case TYPE_UNKNOWN:
-			break;
-		}
-	} else if ((g = FindGlobalVariable (token))) {
-		// Global variable
-		b->Write (DH_PUSHGLOBALVAR);
-		b->Write (g->index);
-	} else {
-		// If nothing else, check for literal
-		switch (reqtype) {
-		case TYPE_VOID:
-		case TYPE_UNKNOWN:
-			ParserError ("unknown identifier `%s` (expected keyword, function or variable)", token.chars());
-			break;
-		case TYPE_BOOL:
-		case TYPE_INT: {
-			MustNumber (true);
-			
-			// All values are written unsigned - thus we need to write the value's
-			// absolute value, followed by an unary minus for negatives.
-			b->Write (DH_PUSHNUMBER);
-			
-			long v = atol (token);
-			b->Write (static_cast<word> (abs (v)));
-			if (v < 0)
-				b->Write (DH_UNARYMINUS);
-			break;
-		}
-		case TYPE_STRING:
-			// PushToStringTable either returns the string index of the
-			// string if it finds it in the table, or writes it to the
-			// table and returns it index if it doesn't find it there.
-			MustString (true);
-			b->WriteString (token);
-			break;
-		}
-	}
-	
-	// Negate it now if desired
-	if (negate)
-		b->Write (DH_NEGATELOGICAL);
-	
-	return b;
-}
-
-// ============================================================================
-// Parses an assignment. An assignment starts with a variable name, followed
-// by an assignment operator, followed by an expression value. Expects current
-// token to be the name of the variable, and expects the variable to be given.
-DataBuffer* ScriptReader::ParseAssignment (ScriptVar* var) {
-	bool global = !var->statename.len ();
-	
-	// Get an operator
-	MustNext ();
-	int oper = ParseOperator ();
-	if (!IsAssignmentOperator (oper))
-		ParserError ("expected assignment operator");
-	
-	if (g_CurMode == MODE_TOPLEVEL) // TODO: lift this restriction
-		ParserError ("can't alter variables at top level");
-	
-	// Parse the right operand
-	MustNext ();
-	DataBuffer* retbuf = new DataBuffer;
-	DataBuffer* expr = ParseExpression (var->type);
-	
-	// <<= and >>= do not have data headers. Solution: expand them.
-	// a <<= b -> a = a << b
-	// a >>= b -> a = a >> b
-	if (oper == OPER_ASSIGNLEFTSHIFT || oper == OPER_ASSIGNRIGHTSHIFT) {
-		retbuf->Write (global ? DH_PUSHGLOBALVAR : DH_PUSHLOCALVAR);
-		retbuf->Write (var->index);
-		retbuf->Merge (expr);
-		retbuf->Write ((oper == OPER_ASSIGNLEFTSHIFT) ? DH_LSHIFT : DH_RSHIFT);
-		retbuf->Write (global ? DH_ASSIGNGLOBALVAR : DH_ASSIGNLOCALVAR);
-		retbuf->Write (var->index);
-	} else {
-		retbuf->Merge (expr);
-		long dh = DataHeaderByOperator (var, oper);
-		retbuf->Write (dh);
-		retbuf->Write (var->index);
-	}
-	
-	return retbuf;
-}
-
-void ScriptReader::PushScope () {
-	g_ScopeCursor++;
-	if (g_ScopeCursor >= MAX_SCOPE)
-		ParserError ("too deep scope");
-	
-	ScopeInfo* info = &SCOPE(0);
-	info->type = SCOPETYPE_UNKNOWN;
-	info->mark1 = 0;
-	info->mark2 = 0;
-	info->buffer1 = NULL;
-	info->casecursor = -1;
-	for (int i = 0; i < MAX_CASE; i++) {
-		info->casemarks[i] = MAX_MARKS;
-		info->casebuffers[i] = NULL;
-		info->casenumbers[i] = -1;
-	}
-}
-
-DataBuffer* ScriptReader::ParseStatement (ObjWriter* w) {
-	if (FindConstant (token)) // There should not be constants here.
-		ParserError ("invalid use for constant\n");
-	
-	// If it's a variable, expect assignment.
-	if (ScriptVar* var = FindGlobalVariable (token))
-		return ParseAssignment (var);
-	
-	return NULL;
-}
-
-void ScriptReader::AddSwitchCase (ObjWriter* w, DataBuffer* b) {
-	ScopeInfo* info = &SCOPE(0);
-	
-	info->casecursor++;
-	if (info->casecursor >= MAX_CASE)
-		ParserError ("too many cases in one switch");
-	
-	// Init a mark for the case buffer
-	int m = w->AddMark ("");
-	info->casemarks[info->casecursor] = m;
-	
-	// Add a reference to the mark. "case" and "default" both
-	// add the necessary bytecode before the reference.
-	if (b)
-		b->AddMarkReference (m);
-	else
-		w->AddReference (m);
-	
-	// Init a buffer for the case block and tell the object
-	// writer to record all written data to it.
-	info->casebuffers[info->casecursor] = w->SwitchBuffer = new DataBuffer;
-}
-
-constinfo_t* FindConstant (str token) {
-	for (uint i = 0; i < g_ConstInfo.size(); i++)
-		if (g_ConstInfo[i].name == token)
-			return &g_ConstInfo[i];
-	return NULL;
-}
\ No newline at end of file
--- a/preprocessor.cxx	Wed Jan 02 23:57:46 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,126 +0,0 @@
-/*
- *	botc source code
- *	Copyright (C) 2012 Santeri `Dusk` Piippo
- *	All rights reserved.
- *	
- *	Redistribution and use in source and binary forms, with or without
- *	modification, are permitted provided that the following conditions are met:
- *	
- *	1. Redistributions of source code must retain the above copyright notice,
- *	   this list of conditions and the following disclaimer.
- *	2. Redistributions in binary form must reproduce the above copyright notice,
- *	   this list of conditions and the following disclaimer in the documentation
- *	   and/or other materials provided with the distribution.
- *	3. Neither the name of the developer nor the names of its contributors may
- *	   be used to endorse or promote products derived from this software without
- *	   specific prior written permission.
- *	4. Redistributions in any form must be accompanied by information on how to
- *	   obtain complete source code for the software and any accompanying
- *	   software that uses the software. The source code must either be included
- *	   in the distribution or be available for no more than the cost of
- *	   distribution plus a nominal fee, and must be freely redistributable
- *	   under reasonable conditions. For an executable file, complete source
- *	   code means the source code for all modules it contains. It does not
- *	   include source code for modules or files that typically accompany the
- *	   major components of the operating system on which the executable file
- *	   runs.
- *	
- *	THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- *	AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- *	IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- *	ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
- *	LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- *	CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- *	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- *	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- *	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- *	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- *	POSSIBILITY OF SUCH DAMAGE.
- */
-
-#define __PARSER_CXX__
-
-#include <stdio.h>
-#include <stdlib.h>
-#include "common.h"
-#include "str.h"
-#include "scriptreader.h"
-
-/* Since the preprocessor is *called* from ReadChar and I don't want
- * to worry about recursive preprocessing, the preprocessor uses its
- * own bare-bones variant of the function for file reading.
- */
-char ScriptReader::PPReadChar () {
-	char c;
-	if (!fread (&c, sizeof (char), 1, fp[fc]))
-		return 0;
-	curchar[fc]++;
-	return c;
-}
-
-void ScriptReader::PPMustChar (char c) {
-	char d = PPReadChar ();
-	if (c != d)
-		ParserError ("expected `%c`, got `%d`", c, d);
-}
-
-// ============================================================================
-// Reads a word until whitespace
-str ScriptReader::PPReadWord (char &term) {
-	str word;
-	while (1) {
-		char c = PPReadChar();
-		if (feof (fp[fc]) || (IsCharWhitespace (c) && word.len ())) {
-			term = c;
-			break;
-		}
-		word += c;
-	}
-	return word;
-}
-
-// ============================================================================
-// Preprocess any directives found in the script file
-void ScriptReader::PreprocessDirectives () {
-	size_t spos = ftell (fp[fc]);
-	if (!DoDirectivePreprocessing ())
-		fseek (fp[fc], spos, SEEK_SET);
-}
-
-/* ============================================================================
- * Returns true if the pre-processing was successful, false if not.
- * If pre-processing was successful, the file pointer remains where
- * it was, if not, it's pushed back to where it was before preprocessing
- * took place and is parsed normally.
- */
-bool ScriptReader::DoDirectivePreprocessing () {
-	char trash;
-	// Directives start with a pound sign
-	if (PPReadChar() != '#')
-		return false;
-	
-	// Read characters until next whitespace to
-	// build the name of the directive
-	str directive = PPReadWord (trash);
-	
-	// Now check the directive name against known names
-	if (directive == "include") {
-		// #include-directive
-		char terminator;
-		str file = PPReadWord (terminator);
-		
-		if (!file.len())
-			ParserError ("expected file name for #include, got nothing instead");
-		OpenFile (file);
-		return true;
-	} else if (directive == "neurosphere") {
-		// #neurosphere - activates neurosphere compatibility, aka stuff
-		// that is still WIP and what main zandronum does not yet support.
-		// Most end users should never need this.
-		g_Neurosphere = true;
-		return true;
-	}
-	
-	ParserError ("unknown directive `#%s`!", directive.chars());
-	return false;
-}
\ No newline at end of file
--- a/scriptreader.cxx	Wed Jan 02 23:57:46 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,412 +0,0 @@
-/*
- *	botc source code
- *	Copyright (C) 2012 Santeri `Dusk` Piippo
- *	All rights reserved.
- *	
- *	Redistribution and use in source and binary forms, with or without
- *	modification, are permitted provided that the following conditions are met:
- *	
- *	1. Redistributions of source code must retain the above copyright notice,
- *	   this list of conditions and the following disclaimer.
- *	2. Redistributions in binary form must reproduce the above copyright notice,
- *	   this list of conditions and the following disclaimer in the documentation
- *	   and/or other materials provided with the distribution.
- *	3. Neither the name of the developer nor the names of its contributors may
- *	   be used to endorse or promote products derived from this software without
- *	   specific prior written permission.
- *	4. Redistributions in any form must be accompanied by information on how to
- *	   obtain complete source code for the software and any accompanying
- *	   software that uses the software. The source code must either be included
- *	   in the distribution or be available for no more than the cost of
- *	   distribution plus a nominal fee, and must be freely redistributable
- *	   under reasonable conditions. For an executable file, complete source
- *	   code means the source code for all modules it contains. It does not
- *	   include source code for modules or files that typically accompany the
- *	   major components of the operating system on which the executable file
- *	   runs.
- *	
- *	THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- *	AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- *	IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- *	ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
- *	LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- *	CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- *	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- *	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- *	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- *	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- *	POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include "string.h"
-#include "str.h"
-#include "common.h"
-#include "scriptreader.h"
-
-#define STORE_POSITION \
-	bool _atnewline = atnewline; \
-	unsigned int _curline = curline[fc]; \
-	unsigned int _curchar = curchar[fc];
-
-#define RESTORE_POSITION \
-	atnewline = _atnewline; \
-	curline[fc] = _curline; \
-	curchar[fc] = _curchar;
-
-// ============================================================================
-ScriptReader::ScriptReader (str path) {
-	token = "";
-	prevtoken = "";
-	prevpos = 0;
-	fc = -1;
-	
-	for (unsigned int u = 0; u < MAX_FILESTACK; u++)
-		fp[u] = NULL;
-	
-	OpenFile (path);
-	commentmode = 0;
-}
-
-// ============================================================================
-ScriptReader::~ScriptReader () {
-	// If comment mode is 2 by the time the file ended, the
-	// comment was left unterminated. 1 is no problem, since
-	// it's terminated by newlines anyway.
-	if (commentmode == 2)
-		ParserError ("unterminated `/*`-style comment");
-	
-	for (unsigned int u = 0; u < MAX_FILESTACK; u++) {
-		if (fp[u]) {
-			ParserWarning ("file idx %u remained open after parsing", u);
-			CloseFile (u);
-		}
-	}
-}
-
-// ============================================================================
-// Opens a file and pushes its pointer to stack
-void ScriptReader::OpenFile (str path) {
-	if (fc+1 >= MAX_FILESTACK) 
-		ParserError ("supposed to open file `%s` but file stack is full! do you have recursive `#include` directives?",
-			path.chars());
-	
-	// Save the position first.
-	if (fc != -1) {
-		savedpos[fc] = ftell (fp[fc]);
-	}
-	
-	fc++;
-	
-	fp[fc] = fopen (path, "r");
-	if (!fp[fc]) {
-		ParserError ("couldn't open %s for reading!\n", path.chars ());
-		exit (1);
-	}
-	
-	fseek (fp[fc], 0, SEEK_SET);
-	filepath[fc] = path.chars();
-	curline[fc] = 1;
-	curchar[fc] = 1;
-	pos[fc] = 0;
-	atnewline = 0;
-}
-
-// ============================================================================
-// Closes the current file
-void ScriptReader::CloseFile (unsigned int u) {
-	if (u >= MAX_FILESTACK)
-		u = fc;
-	
-	if (!fp[u])
-		return;
-	
-	fclose (fp[u]);
-	fp[u] = NULL;
-	fc--;
-	
-	if (fc != -1)
-		fseek (fp[fc], savedpos[fc], SEEK_SET);
-}
-
-// ============================================================================
-char ScriptReader::ReadChar () {
-	if (feof (fp[fc]))
-		return 0;
-	
-	char c;
-	if (!fread (&c, 1, 1, fp[fc]))
-		return 0;
-	
-	// We're at a newline, thus next char read will begin the next line
-	if (atnewline) {
-		atnewline = false;
-		curline[fc]++;
-		curchar[fc] = 0; // gets incremented to 1
-	}
-	
-	if (c == '\n') {
-		atnewline = true;
-		
-		// Check for pre-processor directives
-		PreprocessDirectives ();
-	}
-	
-	curchar[fc]++;
-	return c;
-}
-
-// ============================================================================
-// Peeks the next character
-char ScriptReader::PeekChar (int offset) {
-	// Store current position
-	long curpos = ftell (fp[fc]);
-	STORE_POSITION
-	
-	// Forward by offset
-	fseek (fp[fc], offset, SEEK_CUR);
-	
-	// Read the character
-	char* c = (char*)malloc (sizeof (char));
-	
-	if (!fread (c, sizeof (char), 1, fp[fc])) {
-		fseek (fp[fc], curpos, SEEK_SET);
-		return 0;
-	}
-	
-	// Rewind back
-	fseek (fp[fc], curpos, SEEK_SET);
-	RESTORE_POSITION
-	
-	return c[0];
-}
-
-// ============================================================================
-// Read a token from the file buffer. Returns true if token was found, false if not.
-bool ScriptReader::Next (bool peek) {
-	prevpos = ftell (fp[fc]);
-	str tmp = "";
-	
-	while (1) {
-		// Check end-of-file
-		if (feof (fp[fc])) {
-			// If we're just peeking, we shouldn't
-			// actually close anything.. 
-			if (peek)
-				break;
-			
-			CloseFile ();
-			if (fc == -1)
-				break;
-		}
-		
-		// Check if the next token possibly starts a comment.
-		if (PeekChar () == '/' && !tmp.len()) {
-			char c2 = PeekChar (1);
-			// C++-style comment
-			if (c2 == '/')
-				commentmode = 1;
-			else if (c2 == '*')
-				commentmode = 2;
-			
-			// We don't need to actually read in the
-			// comment characters, since they will get
-			// ignored due to comment mode anyway.
-		}
-		
-		c = ReadChar ();
-		
-		// If this is a comment we're reading, check if this character
-		// gets the comment terminated, otherwise ignore it.
-		if (commentmode > 0) {
-			if (commentmode == 1 && c == '\n') {
-				// C++-style comments are terminated by a newline
-				commentmode = 0;
-				continue;
-			} else if (commentmode == 2 && c == '*') {
-				// C-style comments are terminated by a `*/`
-				if (PeekChar() == '/') {
-					commentmode = 0;
-					ReadChar ();
-				}
-			}
-			
-			// Otherwise, ignore it.
-			continue;
-		}
-		
-		// Non-alphanumber characters (sans underscore) break the word too.
-		// If there was prior data, the delimeter pushes the cursor back so
-		// that the next character will be the same delimeter. If there isn't,
-		// the delimeter itself is included (and thus becomes a token itself.)
-		if ((c >= 33 && c <= 47) ||
-			(c >= 58 && c <= 64) ||
-			(c >= 91 && c <= 96 && c != '_') ||
-			(c >= 123 && c <= 126)) {
-			if (tmp.len())
-				fseek (fp[fc], ftell (fp[fc]) - 1, SEEK_SET);
-			else
-				tmp += c;
-			break;
-		}
-		
-		if (IsCharWhitespace (c)) {
-			// Don't break if we haven't gathered anything yet.
-			if (tmp.len())
-				break;
-		} else {
-			tmp += c;
-		}
-	}
-	
-	// If we got nothing here, read failed. This should
-	// only happen in the case of EOF.
-	if (!tmp.len()) {
-		token = "";
-		return false;
-	}
-	
-	pos[fc]++;
-	prevtoken = token;
-	token = tmp;
-	return true;
-}
-
-// ============================================================================
-// Returns the next token without advancing the cursor.
-str ScriptReader::PeekNext (int offset) {
-	// Store current information
-	str storedtoken = token;
-	int cpos = ftell (fp[fc]);
-	STORE_POSITION
-	
-	// Advance on the token.
-	while (offset >= 0) {
-		if (!Next (true))
-			return "";
-		offset--;
-	}
-	
-	str tmp = token;
-	
-	// Restore position
-	fseek (fp[fc], cpos, SEEK_SET);
-	pos[fc]--;
-	token = storedtoken;
-	RESTORE_POSITION
-	return tmp;
-}
-
-// ============================================================================
-void ScriptReader::Seek (unsigned int n, int origin) {
-	switch (origin) {
-	case SEEK_SET:
-		fseek (fp[fc], 0, SEEK_SET);
-		pos[fc] = 0;
-		break;
-	case SEEK_CUR:
-		break;
-	case SEEK_END:
-		printf ("ScriptReader::Seek: SEEK_END not yet supported.\n");
-		break;
-	}
-	
-	for (unsigned int i = 0; i < n+1; i++)
-		Next();
-}
-
-// ============================================================================
-void ScriptReader::MustNext (const char* c) {
-	if (!Next()) {
-		if (strlen (c))
-			ParserError ("expected `%s`, reached end of file instead\n", c);
-		else
-			ParserError ("expected a token, reached end of file instead\n");
-	}
-	
-	if (strlen (c))
-		MustThis (c);
-}
-
-// ============================================================================
-void ScriptReader::MustThis (const char* c) {
-	if (token != c)
-		ParserError ("expected `%s`, got `%s` instead", c, token.chars());
-}
-
-// ============================================================================
-void ScriptReader::ParserError (const char* message, ...) {
-	PERFORM_FORMAT (message, outmessage);
-	ParserMessage ("\nError: ", outmessage);
-	exit (1);
-}
-
-// ============================================================================
-void ScriptReader::ParserWarning (const char* message, ...) {
-	PERFORM_FORMAT (message, outmessage);
-	ParserMessage ("Warning: ", outmessage);
-}
-
-// ============================================================================
-void ScriptReader::ParserMessage (const char* header, char* message) {
-	if (fc >= 0 && fc < MAX_FILESTACK)
-		fprintf (stderr, "%s%s:%u:%u: %s\n",
-			header, filepath[fc], curline[fc], curchar[fc], message);
-	else
-		fprintf (stderr, "%s%s\n", header, message);
-}
-
-// ============================================================================
-// if gotquote == 1, the current token already holds the quotation mark.
-void ScriptReader::MustString (bool gotquote) {
-	if (gotquote)
-		MustThis ("\"");
-	else
-		MustNext ("\"");
-	
-	str string;
-	// Keep reading characters until we find a terminating quote.
-	while (1) {
-		// can't end here!
-		if (feof (fp[fc]))
-			ParserError ("unterminated string");
-		
-		char c = ReadChar ();
-		if (c == '"')
-			break;
-		
-		string += c;
-	}
-	
-	token = string;
-}
-
-// ============================================================================
-void ScriptReader::MustNumber (bool fromthis) {
-	if (!fromthis)
-		MustNext ();
-	
-	str num = token;
-	if (num == "-") {
-		MustNext ();
-		num += token;
-	}
-	
-	// "true" and "false" are valid numbers
-	if (!token.icompare ("true"))
-		token = "1";
-	else if (!token.icompare ("false"))
-		token = "0";
-	else {
-		if (!token.isnumber())
-			ParserError ("expected a number, got `%s`", num.chars());
-		
-		str check;
-		check.appendformat ("%d", atoi (num));
-		if (token != check)
-			ParserWarning ("integer too large: %s -> %s", num.chars(), check.chars());
-		
-		token = num;
-	}
-}
\ No newline at end of file
--- a/scriptreader.h	Wed Jan 02 23:57:46 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,211 +0,0 @@
-/*
- *	botc source code
- *	Copyright (C) 2012 Santeri `Dusk` Piippo
- *	All rights reserved.
- *	
- *	Redistribution and use in source and binary forms, with or without
- *	modification, are permitted provided that the following conditions are met:
- *	
- *	1. Redistributions of source code must retain the above copyright notice,
- *	   this list of conditions and the following disclaimer.
- *	2. Redistributions in binary form must reproduce the above copyright notice,
- *	   this list of conditions and the following disclaimer in the documentation
- *	   and/or other materials provided with the distribution.
- *	3. Neither the name of the developer nor the names of its contributors may
- *	   be used to endorse or promote products derived from this software without
- *	   specific prior written permission.
- *	4. Redistributions in any form must be accompanied by information on how to
- *	   obtain complete source code for the software and any accompanying
- *	   software that uses the software. The source code must either be included
- *	   in the distribution or be available for no more than the cost of
- *	   distribution plus a nominal fee, and must be freely redistributable
- *	   under reasonable conditions. For an executable file, complete source
- *	   code means the source code for all modules it contains. It does not
- *	   include source code for modules or files that typically accompany the
- *	   major components of the operating system on which the executable file
- *	   runs.
- *	
- *	THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- *	AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- *	IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- *	ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
- *	LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- *	CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- *	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- *	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- *	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- *	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- *	POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef __SCRIPTREADER_H__
-#define __SCRIPTREADER_H__
-
-#include <stdio.h>
-#include "str.h"
-#include "commands.h"
-#include "objwriter.h"
-
-#define MAX_FILESTACK 8
-#define MAX_SCOPE 32
-#define MAX_CASE 64
-
-class ScriptVar;
-
-// Operators
-enum operator_e {
-	OPER_ADD,
-	OPER_SUBTRACT,
-	OPER_MULTIPLY,
-	OPER_DIVIDE,
-	OPER_MODULUS,
-	OPER_ASSIGN,
-	OPER_ASSIGNADD,
-	OPER_ASSIGNSUB,
-	OPER_ASSIGNMUL,
-	OPER_ASSIGNDIV,
-	OPER_ASSIGNMOD, // -- 10
-	OPER_EQUALS,
-	OPER_NOTEQUALS,
-	OPER_LESSTHAN,
-	OPER_GREATERTHAN,
-	OPER_LESSTHANEQUALS,
-	OPER_GREATERTHANEQUALS,
-	OPER_LEFTSHIFT,
-	OPER_RIGHTSHIFT,
-	OPER_ASSIGNLEFTSHIFT,
-	OPER_ASSIGNRIGHTSHIFT, // -- 20
-	OPER_OR,
-	OPER_AND,
-	OPER_BITWISEOR,
-	OPER_BITWISEAND,
-	OPER_BITWISEEOR,
-	OPER_TERNARY,
-	OPER_STRLEN,
-};
-
-// Mark types
-enum marktype_e {
-	MARKTYPE_LABEL,
-	MARKTYPE_IF,
-	MARKTYPE_INTERNAL, // internal structures
-};
-
-// Block types
-enum scopetype_e {
-	SCOPETYPE_UNKNOWN,
-	SCOPETYPE_IF,
-	SCOPETYPE_WHILE,
-	SCOPETYPE_FOR,
-	SCOPETYPE_DO,
-	SCOPETYPE_SWITCH,
-	SCOPETYPE_ELSE,
-};
-
-// ============================================================================
-// Meta-data about blocks
-struct ScopeInfo {
-	unsigned int mark1;
-	unsigned int mark2;
-	scopetype_e type;
-	DataBuffer* buffer1;
-	
-	// switch-related stuff
-	// Which case are we at?
-	short casecursor;
-	
-	// Marks to case-blocks
-	int casemarks[MAX_CASE];
-	
-	// Numbers of the case labels
-	int casenumbers[MAX_CASE];
-	
-	// actual case blocks
-	DataBuffer* casebuffers[MAX_CASE];
-	
-	// What is the current buffer of the block?
-	DataBuffer* recordbuffer;
-};
-
-// ============================================================================
-typedef struct {
-	str name;
-	type_e type;
-	str val;
-} constinfo_t;
-
-// ============================================================================
-// The script reader reads the script, parses it and tells the object writer
-// the bytecode it needs to write to file.
-class ScriptReader {
-public:
-	// ====================================================================
-	// MEMBERS
-	FILE* fp[MAX_FILESTACK];
-	char* filepath[MAX_FILESTACK];
-	int fc;
-	
-	unsigned int pos[MAX_FILESTACK];
-	unsigned int curline[MAX_FILESTACK];
-	unsigned int curchar[MAX_FILESTACK];
-	ScopeInfo scopestack[MAX_SCOPE];
-	long savedpos[MAX_FILESTACK]; // filepointer cursor position
-	str token;
-	int commentmode;
-	long prevpos;
-	str prevtoken;
-	
-	// ====================================================================
-	// METHODS
-	// scriptreader.cxx:
-	ScriptReader (str path);
-	~ScriptReader ();
-	void OpenFile (str path);
-	void CloseFile (unsigned int u = MAX_FILESTACK);
-	char ReadChar ();
-	char PeekChar (int offset = 0);
-	bool Next (bool peek = false);
-	void Prev ();
-	str PeekNext (int offset = 0);
-	void Seek (unsigned int n, int origin);
-	void MustNext (const char* c = "");
-	void MustThis (const char* c);
-	void MustString (bool gotquote = false);
-	void MustNumber (bool fromthis = false);
-	void MustBool ();
-	bool BoolValue ();
-	
-	void ParserError (const char* message, ...);
-	void ParserWarning (const char* message, ...);
-	
-	// parser.cxx:
-	void ParseBotScript (ObjWriter* w);
-	DataBuffer* ParseCommand (CommandDef* comm);
-	DataBuffer* ParseExpression (type_e reqtype);
-	DataBuffer* ParseAssignment (ScriptVar* var);
-	int ParseOperator (bool peek = false);
-	DataBuffer* ParseExprValue (type_e reqtype);
-	str ParseFloat ();
-	void PushScope ();
-	
-	// preprocessor.cxx:
-	void PreprocessDirectives ();
-	void PreprocessMacros ();
-	DataBuffer* ParseStatement (ObjWriter* w);
-	void AddSwitchCase (ObjWriter* w, DataBuffer* b);
-	
-private:
-	bool atnewline;
-	char c;
-	void ParserMessage (const char* header, char* message);
-	
-	bool DoDirectivePreprocessing ();
-	char PPReadChar ();
-	void PPMustChar (char c);
-	str PPReadWord (char &term);
-};
-
-constinfo_t* FindConstant (str token);
-extern bool g_Neurosphere;
-
-#endif // __SCRIPTREADER_H__
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/array.h	Fri Jan 10 16:11:49 2014 +0200
@@ -0,0 +1,190 @@
+/*
+ *	botc source code
+ *	Copyright (C) 2012 Santeri `Dusk` Piippo
+ *	All rights reserved.
+ *	
+ *	Redistribution and use in source and binary forms, with or without
+ *	modification, are permitted provided that the following conditions are met:
+ *	
+ *	1. Redistributions of source code must retain the above copyright notice,
+ *	   this list of conditions and the following disclaimer.
+ *	2. Redistributions in binary form must reproduce the above copyright notice,
+ *	   this list of conditions and the following disclaimer in the documentation
+ *	   and/or other materials provided with the distribution.
+ *	3. Neither the name of the developer nor the names of its contributors may
+ *	   be used to endorse or promote products derived from this software without
+ *	   specific prior written permission.
+ *	4. Redistributions in any form must be accompanied by information on how to
+ *	   obtain complete source code for the software and any accompanying
+ *	   software that uses the software. The source code must either be included
+ *	   in the distribution or be available for no more than the cost of
+ *	   distribution plus a nominal fee, and must be freely redistributable
+ *	   under reasonable conditions. For an executable file, complete source
+ *	   code means the source code for all modules it contains. It does not
+ *	   include source code for modules or files that typically accompany the
+ *	   major components of the operating system on which the executable file
+ *	   runs.
+ *	
+ *	THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ *	AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ *	IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ *	ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ *	LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *	CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ *	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ *	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ *	POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "common.h"
+
+#define ITERATE_SUBSCRIPTS(link) \
+	for (link = data; link; link = link->next)
+
+#define foreach_counter(NAME) \
+	(int)(reinterpret_cast<int> (foreach_counter##NAME) / sizeof (foreach_counter##NAME))
+#define foreach(T,NAME,ARRAY) \
+	if (ARRAY.size() > 0) for (T NAME = ARRAY[0], *foreach_counter##NAME = 0; \
+		foreach_counter(NAME) < (int)(ARRAY.size()); \
+		NAME = ARRAY[reinterpret_cast<int> (++foreach_counter##NAME) / sizeof (foreach_counter##NAME)])
+
+// Single element of an array
+template <class T> class arrayElement {
+public:
+	T value;
+	arrayElement<T>* next;
+	
+	arrayElement () {
+		next = NULL;
+	}
+};
+
+// Dynamic array
+template <class T> class array {
+public:
+	array () {
+		data = NULL;
+	}
+	
+	array (T* stuff, unsigned int c) {
+		printf ("%d elements\n", c);
+		data = NULL;
+		
+		for (unsigned int i = 0; i < c; i++)
+			push (stuff[c]);
+	}
+	
+	~array () {
+		if (data)
+			deleteElement (data);
+	}
+	
+	void push (T stuff) {
+		arrayElement<T>* e = new arrayElement<T>;
+		e->value = stuff;
+		e->next = NULL;
+		
+		if (!data) {
+			data = e;
+			return;
+		}
+		
+		arrayElement<T>* link;
+		for (link = data; link && link->next; link = link->next);
+		link->next = e;
+	}
+	
+	T pop () {
+		int pos = size() - 1;
+		if (pos == -1)
+			error ("array::pop: tried to pop an array with no elements\n");
+		T res = subscript (pos);
+		remove (pos);
+		return res;
+	}
+	
+	void remove (unsigned int pos) {
+		if (!data)
+			error ("tried to use remove on an array with no elements");
+		
+		if (pos == 0) {
+			// special case for first element
+			arrayElement<T>* first = data;
+			data = data->next;
+			delete first;
+			return;
+		}
+		
+		arrayElement<T>* link = data;
+		unsigned int x = 0;
+		while (link->next) {
+			if (x == pos - 1)
+				break;
+			link = link->next;
+			x++;
+		}
+		if (!link)
+			error ("no such element in array\n");
+		
+		arrayElement<T>* nextlink = link->next->next;
+		delete link->next;
+		link->next = nextlink;
+	}
+	
+	unsigned int size () {
+		unsigned int x = 0;
+		arrayElement<T>* link;
+		ITERATE_SUBSCRIPTS(link)
+			x++;
+		return x;
+	}
+	
+	T& subscript (unsigned int i) {
+		arrayElement<T>* link;
+		unsigned int x = 0;
+		ITERATE_SUBSCRIPTS(link) {
+			if (x == i)
+				return link->value;
+			x++;
+		}
+		
+		error ("array: tried to access subscript %u in an array of %u elements\n", i, x);
+		return data->value;
+	}
+	
+	T* out () {
+		int s = size();
+		T* out = new T[s];
+		unsigned int x = 0;
+		
+		arrayElement<T>* link;
+		ITERATE_SUBSCRIPTS(link) {
+			out[x] = link->value;
+			x++;
+		}
+		
+		return out;
+	}
+	
+	T& operator [] (const unsigned int i) {
+		return subscript (i);
+	}
+	
+	void operator << (const T stuff) {
+		push (stuff);
+	}
+	
+private:
+	void deleteElement (arrayElement<T>* e) {
+		if (e->next)
+			deleteElement (e->next);
+		delete e;
+	}
+	
+	arrayElement<T>* data;
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/botcommands.h	Fri Jan 10 16:11:49 2014 +0200
@@ -0,0 +1,173 @@
+//-----------------------------------------------------------------------------
+//
+// Skulltag Source
+// Copyright (C) 2002 Brad Carney
+// Copyright (C) 2007-2012 Skulltag Development Team
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice,
+//    this list of conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+//    this list of conditions and the following disclaimer in the documentation
+//    and/or other materials provided with the distribution.
+// 3. Neither the name of the Skulltag Development Team nor the names of its
+//    contributors may be used to endorse or promote products derived from this
+//    software without specific prior written permission.
+// 4. Redistributions in any form must be accompanied by information on how to
+//    obtain complete source code for the software and any accompanying
+//    software that uses the software. The source code must either be included
+//    in the distribution or be available for no more than the cost of
+//    distribution plus a nominal fee, and must be freely redistributable
+//    under reasonable conditions. For an executable file, complete source
+//    code means the source code for all modules it contains. It does not
+//    include source code for modules or files that typically accompany the
+//    major components of the operating system on which the executable file
+//    runs.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+// Date created:  5/18/04
+//
+//
+// Filename: botcommands.h
+//
+// Description: Contains bot structures and prototypes
+// [Dusk] Clipped stuff that botc doesn't need.
+//
+//-----------------------------------------------------------------------------
+
+#ifndef __BOTCOMMANDS_H__
+#define __BOTCOMMANDS_H__
+
+#include "bots.h"
+
+//*****************************************************************************
+//  DEFINES
+
+#define	SETENEMY_LASTSEEN		0
+#define	SETENEMY_LASTSHOTBY		1
+
+// Different results for pathing commands.
+#define	PATH_UNREACHABLE			-1
+#define	PATH_INCOMPLETE				0
+#define	PATH_COMPLETE				1
+#define	PATH_REACHEDGOAL			2
+
+// This is the size of the return string for the bot command functions.
+#define	BOTCMD_RETURNSTRING_SIZE	256
+
+//*****************************************************************************
+typedef enum
+{
+	BOTCMD_CHANGESTATE,									// Basic botcmd utility functions.
+	BOTCMD_DELAY,
+	BOTCMD_RAND,
+	BOTCMD_STRINGSAREEQUAL,
+	BOTCMD_LOOKFORPOWERUPS,								// Search functions.
+	BOTCMD_LOOKFORWEAPONS,
+	BOTCMD_LOOKFORAMMO,
+	BOTCMD_LOOKFORBASEHEALTH,
+	BOTCMD_LOOKFORBASEARMOR,
+	BOTCMD_LOOKFORSUPERHEALTH,
+	BOTCMD_LOOKFORSUPERARMOR,				/* 10 */
+	BOTCMD_LOOKFORPLAYERENEMIES,
+	BOTCMD_GETCLOSESTPLAYERENEMY,
+	BOTCMD_MOVELEFT,									// Movement functions.
+	BOTCMD_MOVERIGHT,
+	BOTCMD_MOVEFORWARD,
+	BOTCMD_MOVEBACKWARDS,
+	BOTCMD_STOPMOVEMENT,
+	BOTCMD_STOPFORWARDMOVEMENT,
+	BOTCMD_STOPSIDEWAYSMOVEMENT,
+	BOTCMD_CHECKTERRAIN,					/* 20 */
+	BOTCMD_PATHTOGOAL,									// Pathing functions.
+	BOTCMD_PATHTOLASTKNOWNENEMYPOSITION,
+	BOTCMD_PATHTOLASTHEARDSOUND,
+	BOTCMD_ROAM,
+	BOTCMD_GETPATHINGCOSTTOITEM,
+	BOTCMD_GETDISTANCETOITEM,
+	BOTCMD_GETITEMNAME,
+	BOTCMD_ISITEMVISIBLE,
+	BOTCMD_SETGOAL,
+	BOTCMD_BEGINAIMINGATENEMY,				/* 30 */	// Aiming functions.
+	BOTCMD_STOPAIMINGATENEMY,
+	BOTCMD_TURN,
+	BOTCMD_GETCURRENTANGLE,
+	BOTCMD_SETENEMY,									// Enemy functions.
+	BOTCMD_CLEARENEMY,
+	BOTCMD_ISENEMYALIVE,
+	BOTCMD_ISENEMYVISIBLE,
+	BOTCMD_GETDISTANCETOENEMY,
+	BOTCMD_GETPLAYERDAMAGEDBY,
+	BOTCMD_GETENEMYINVULNERABILITYTICKS,	/* 40 */
+	BOTCMD_FIREWEAPON,									// Weapon functions.
+	BOTCMD_BEGINFIRINGWEAPON,
+	BOTCMD_STOPFIRINGWEAPON,
+	BOTCMD_GETCURRENTWEAPON,
+	BOTCMD_CHANGEWEAPON,
+	BOTCMD_GETWEAPONFROMITEM,
+	BOTCMD_ISWEAPONOWNED,
+	BOTCMD_ISFAVORITEWEAPON,
+	BOTCMD_SAY,											// Chat functions.
+	BOTCMD_SAYFROMFILE,						/* 50 */
+	BOTCMD_SAYFROMCHATFILE,
+	BOTCMD_BEGINCHATTING,
+	BOTCMD_STOPCHATTING,
+	BOTCMD_CHATSECTIONEXISTS,
+	BOTCMD_CHATSECTIONEXISTSINFILE,
+	BOTCMD_GETLASTCHATSTRING,
+	BOTCMD_GETLASTCHATPLAYER,
+	BOTCMD_GETCHATFREQUENCY,
+	BOTCMD_JUMP,										// Jumping functions.
+	BOTCMD_BEGINJUMPING,					/* 60 */
+	BOTCMD_STOPJUMPING,
+	BOTCMD_TAUNT,										// Other action functions.
+	BOTCMD_RESPAWN,
+	BOTCMD_TRYTOJOINGAME,
+	BOTCMD_ISDEAD,										// Information about self functions.
+	BOTCMD_ISSPECTATING,
+	BOTCMD_GETHEALTH,
+	BOTCMD_GETARMOR,
+	BOTCMD_GETBASEHEALTH,
+	BOTCMD_GETBASEARMOR,					/* 70 */
+	BOTCMD_GETBOTSKILL,									// Botskill functions.
+	BOTCMD_GETACCURACY,
+	BOTCMD_GETINTELLECT,
+	BOTCMD_GETANTICIPATION,
+	BOTCMD_GETEVADE,
+	BOTCMD_GETREACTIONTIME,
+	BOTCMD_GETPERCEPTION,
+	BOTCMD_SETSKILLINCREASE,							// Botskill modifying functions functions.
+	BOTCMD_ISSKILLINCREASED,
+	BOTCMD_SETSKILLDECREASE,				/* 80 */
+	BOTCMD_ISSKILLDECREASED,
+	BOTCMD_GETGAMEMODE,									// Other functions.
+	BOTCMD_GETSPREAD,
+	BOTCMD_GETLASTJOINEDPLAYER,
+	BOTCMD_GETPLAYERNAME,
+	BOTCMD_GETRECEIVEDMEDAL,
+	BOTCMD_ACS_EXECUTE,
+	BOTCMD_GETFAVORITEWEAPON,
+	BOTCMD_SAYFROMLUMP,
+	BOTCMD_SAYFROMCHATLUMP,					/* 90 */
+	BOTCMD_CHATSECTIONEXISTSINLUMP,
+	BOTCMD_CHATSECTIONEXISTSINCHATLUMP,
+
+	NUM_BOTCMDS
+
+} BOTCMD_e;
+
+#endif	// __BOTCOMMANDS_H__
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/bots.h	Fri Jan 10 16:11:49 2014 +0200
@@ -0,0 +1,272 @@
+//-----------------------------------------------------------------------------
+//
+// Skulltag Source
+// Copyright (C) 2002 Brad Carney
+// Copyright (C) 2007-2012 Skulltag Development Team
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice,
+//    this list of conditions and the following disclaimer.
+// 2. Redistributions in binary form must reproduce the above copyright notice,
+//    this list of conditions and the following disclaimer in the documentation
+//    and/or other materials provided with the distribution.
+// 3. Neither the name of the Skulltag Development Team nor the names of its
+//    contributors may be used to endorse or promote products derived from this
+//    software without specific prior written permission.
+// 4. Redistributions in any form must be accompanied by information on how to
+//    obtain complete source code for the software and any accompanying
+//    software that uses the software. The source code must either be included
+//    in the distribution or be available for no more than the cost of
+//    distribution plus a nominal fee, and must be freely redistributable
+//    under reasonable conditions. For an executable file, complete source
+//    code means the source code for all modules it contains. It does not
+//    include source code for modules or files that typically accompany the
+//    major components of the operating system on which the executable file
+//    runs.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
+//
+//
+//
+// Filename: bots.h
+//
+// Description: Contains bot structures and prototypes
+// [Dusk] Cropped out the stuff botc doesn't need.
+//
+//-----------------------------------------------------------------------------
+
+#ifndef __BOTS_H__
+#define __BOTS_H__
+
+//*****************************************************************************
+//  DEFINES
+
+// Maximum number of variables on the bot evaluation stack.
+#define	BOTSCRIPT_STACK_SIZE		8
+
+// Maximum number of botinto structures that can be defines.
+#define	MAX_BOTINFO					128
+
+// Maximum number of states that can appear in a script.
+#define	MAX_NUM_STATES				256
+
+// Maximum number of bot events that can be defined.
+#define	MAX_NUM_EVENTS				32
+
+// Maximum number of global bot events that can be defined.
+#define	MAX_NUM_GLOBAL_EVENTS		32
+
+// Maximum number of global variables that can be defined in a script.
+#define	MAX_SCRIPT_VARIABLES		128
+
+// Maximum number of global arrays that can be defined in a script.
+#define	MAX_SCRIPT_ARRAYS			16
+
+// Maximum number of global arrays that can be defined in a script.
+#define	MAX_SCRIPTARRAY_SIZE		65536
+
+// Maxmimum number of state (local) variables that can appear in a script.
+#define	MAX_STATE_VARIABLES			16
+
+// Maximum number of strings that can appear in a script stringlist.
+#define	MAX_LIST_STRINGS			128
+
+// Maximum length of those strings in the stringlist.
+#define	MAX_STRING_LENGTH			256
+
+// Maximum reaction time for a bot.
+#define	MAX_REACTION_TIME			52
+
+// Maximum number of events the bots can store up that it's waiting to react to.
+#define	MAX_STORED_EVENTS			64
+
+//*****************************************************************************
+typedef enum
+{
+	// Bot skill ratings.
+	BOTSKILL_VERYPOOR,
+	BOTSKILL_POOR,
+	BOTSKILL_LOW,
+	BOTSKILL_MEDIUM,
+	BOTSKILL_HIGH,
+	BOTSKILL_EXCELLENT,
+	BOTSKILL_SUPREME,
+	BOTSKILL_GODLIKE,
+	BOTSKILL_PERFECT,
+
+	NUM_BOT_SKILLS
+
+} BOTSKILL_e;
+
+//*****************************************************************************
+//  STRUCTURES
+//
+
+//*****************************************************************************
+//	These are the botscript data headers that it writes out.
+typedef enum
+{
+	DH_COMMAND,
+	DH_STATEIDX,
+	DH_STATENAME,
+	DH_ONENTER,
+	DH_MAINLOOP,
+	DH_ONEXIT,
+	DH_EVENT,
+	DH_ENDONENTER,
+	DH_ENDMAINLOOP,
+	DH_ENDONEXIT,
+	DH_ENDEVENT,
+	DH_IFGOTO,
+	DH_IFNOTGOTO,
+	DH_GOTO,
+	DH_ORLOGICAL,
+	DH_ANDLOGICAL,
+	DH_ORBITWISE,
+	DH_EORBITWISE,
+	DH_ANDBITWISE,
+	DH_EQUALS,
+	DH_NOTEQUALS,
+	DH_LESSTHAN,
+	DH_LESSTHANEQUALS,
+	DH_GREATERTHAN,
+	DH_GREATERTHANEQUALS,
+	DH_NEGATELOGICAL,
+	DH_LSHIFT,
+	DH_RSHIFT,
+	DH_ADD,
+	DH_SUBTRACT,
+	DH_UNARYMINUS,
+	DH_MULTIPLY,
+	DH_DIVIDE,
+	DH_MODULUS,
+	DH_PUSHNUMBER,
+	DH_PUSHSTRINGINDEX,
+	DH_PUSHGLOBALVAR,
+	DH_PUSHLOCALVAR,
+	DH_DROPSTACKPOSITION,
+	DH_SCRIPTVARLIST,
+	DH_STRINGLIST,
+	DH_INCGLOBALVAR,
+	DH_DECGLOBALVAR,
+	DH_ASSIGNGLOBALVAR,
+	DH_ADDGLOBALVAR,
+	DH_SUBGLOBALVAR,
+	DH_MULGLOBALVAR,
+	DH_DIVGLOBALVAR,
+	DH_MODGLOBALVAR,
+	DH_INCLOCALVAR,
+	DH_DECLOCALVAR,
+	DH_ASSIGNLOCALVAR,
+	DH_ADDLOCALVAR,
+	DH_SUBLOCALVAR,
+	DH_MULLOCALVAR,
+	DH_DIVLOCALVAR,
+	DH_MODLOCALVAR,
+	DH_CASEGOTO,
+	DH_DROP,
+	DH_INCGLOBALARRAY,
+	DH_DECGLOBALARRAY,
+	DH_ASSIGNGLOBALARRAY,
+	DH_ADDGLOBALARRAY,
+	DH_SUBGLOBALARRAY,
+	DH_MULGLOBALARRAY,
+	DH_DIVGLOBALARRAY,
+	DH_MODGLOBALARRAY,
+	DH_PUSHGLOBALARRAY,
+	DH_SWAP,
+	DH_DUP,
+	DH_ARRAYSET,
+
+	NUM_DATAHEADERS
+
+} DATAHEADERS_e;
+
+//*****************************************************************************
+//	These are the different bot events that can be posted to a bot's state.
+typedef enum
+{
+	BOTEVENT_KILLED_BYENEMY,
+	BOTEVENT_KILLED_BYPLAYER,
+	BOTEVENT_KILLED_BYSELF,
+	BOTEVENT_KILLED_BYENVIORNMENT,
+	BOTEVENT_REACHED_GOAL,
+	BOTEVENT_GOAL_REMOVED,
+	BOTEVENT_DAMAGEDBY_PLAYER,
+	BOTEVENT_PLAYER_SAY,
+	BOTEVENT_ENEMY_KILLED,
+	BOTEVENT_RESPAWNED,
+	BOTEVENT_INTERMISSION,
+	BOTEVENT_NEWMAP,
+	BOTEVENT_ENEMY_USEDFIST,
+	BOTEVENT_ENEMY_USEDCHAINSAW,
+	BOTEVENT_ENEMY_FIREDPISTOL,
+	BOTEVENT_ENEMY_FIREDSHOTGUN,
+	BOTEVENT_ENEMY_FIREDSSG,
+	BOTEVENT_ENEMY_FIREDCHAINGUN,
+	BOTEVENT_ENEMY_FIREDMINIGUN,
+	BOTEVENT_ENEMY_FIREDROCKET,
+	BOTEVENT_ENEMY_FIREDGRENADE,
+	BOTEVENT_ENEMY_FIREDRAILGUN,
+	BOTEVENT_ENEMY_FIREDPLASMA,
+	BOTEVENT_ENEMY_FIREDBFG,
+	BOTEVENT_ENEMY_FIREDBFG10K,
+	BOTEVENT_PLAYER_USEDFIST,
+	BOTEVENT_PLAYER_USEDCHAINSAW,
+	BOTEVENT_PLAYER_FIREDPISTOL,
+	BOTEVENT_PLAYER_FIREDSHOTGUN,
+	BOTEVENT_PLAYER_FIREDSSG,
+	BOTEVENT_PLAYER_FIREDCHAINGUN,
+	BOTEVENT_PLAYER_FIREDMINIGUN,
+	BOTEVENT_PLAYER_FIREDROCKET,
+	BOTEVENT_PLAYER_FIREDGRENADE,
+	BOTEVENT_PLAYER_FIREDRAILGUN,
+	BOTEVENT_PLAYER_FIREDPLASMA,
+	BOTEVENT_PLAYER_FIREDBFG,
+	BOTEVENT_PLAYER_FIREDBFG10K,
+	BOTEVENT_USEDFIST,
+	BOTEVENT_USEDCHAINSAW,
+	BOTEVENT_FIREDPISTOL,
+	BOTEVENT_FIREDSHOTGUN,
+	BOTEVENT_FIREDSSG,
+	BOTEVENT_FIREDCHAINGUN,
+	BOTEVENT_FIREDMINIGUN,
+	BOTEVENT_FIREDROCKET,
+	BOTEVENT_FIREDGRENADE,
+	BOTEVENT_FIREDRAILGUN,
+	BOTEVENT_FIREDPLASMA,
+	BOTEVENT_FIREDBFG,
+	BOTEVENT_FIREDBFG10K,
+	BOTEVENT_PLAYER_JOINEDGAME,
+	BOTEVENT_JOINEDGAME,
+	BOTEVENT_DUEL_STARTINGCOUNTDOWN,
+	BOTEVENT_DUEL_FIGHT,
+	BOTEVENT_DUEL_WINSEQUENCE,
+	BOTEVENT_SPECTATING,
+	BOTEVENT_LMS_STARTINGCOUNTDOWN,
+	BOTEVENT_LMS_FIGHT,
+	BOTEVENT_LMS_WINSEQUENCE,
+	BOTEVENT_WEAPONCHANGE,
+	BOTEVENT_ENEMY_BFGEXPLODE,
+	BOTEVENT_PLAYER_BFGEXPLODE,
+	BOTEVENT_BFGEXPLODE,
+	BOTEVENT_RECEIVEDMEDAL,
+
+	NUM_BOTEVENTS
+
+} BOTEVENT_e;
+
+#endif	// __BOTS_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/commands.cxx	Fri Jan 10 16:11:49 2014 +0200
@@ -0,0 +1,217 @@
+/*
+ *	botc source code
+ *	Copyright (C) 2012 Santeri `Dusk` Piippo
+ *	All rights reserved.
+ *	
+ *	Redistribution and use in source and binary forms, with or without
+ *	modification, are permitted provided that the following conditions are met:
+ *	
+ *	1. Redistributions of source code must retain the above copyright notice,
+ *	   this list of conditions and the following disclaimer.
+ *	2. Redistributions in binary form must reproduce the above copyright notice,
+ *	   this list of conditions and the following disclaimer in the documentation
+ *	   and/or other materials provided with the distribution.
+ *	3. Neither the name of the developer nor the names of its contributors may
+ *	   be used to endorse or promote products derived from this software without
+ *	   specific prior written permission.
+ *	4. Redistributions in any form must be accompanied by information on how to
+ *	   obtain complete source code for the software and any accompanying
+ *	   software that uses the software. The source code must either be included
+ *	   in the distribution or be available for no more than the cost of
+ *	   distribution plus a nominal fee, and must be freely redistributable
+ *	   under reasonable conditions. For an executable file, complete source
+ *	   code means the source code for all modules it contains. It does not
+ *	   include source code for modules or files that typically accompany the
+ *	   major components of the operating system on which the executable file
+ *	   runs.
+ *	
+ *	THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ *	AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ *	IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ *	ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ *	LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *	CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ *	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ *	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ *	POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define __COMMANDS_CXX__
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "common.h"
+#include "scriptreader.h"
+#include "str.h"
+#include "commands.h"
+
+// ============================================================================
+// Reads command definitions from commands.def and stores them to memory.
+void ReadCommands () {
+	ScriptReader* r = new ScriptReader ("commands.def");
+	g_CommDef = NULL;
+	CommandDef* curdef = g_CommDef;
+	unsigned int numCommDefs = 0;
+	
+	while (r->PeekNext().len()) {
+		CommandDef* comm = new CommandDef;
+		comm->next = NULL;
+		
+		// Number
+		r->MustNumber ();
+		comm->number = r->token;
+		
+		r->MustNext (":");
+		
+		// Name
+		r->MustNext ();
+		comm->name = r->token;
+		if (IsKeyword (comm->name))
+			r->ParserError ("command name `%s` conflicts with keyword", comm->name.chars());
+		
+		r->MustNext (":");
+		
+		// Return value
+		r->MustNext ();
+		comm->returnvalue = GetTypeByName (r->token);
+		if (comm->returnvalue == -1)
+			r->ParserError ("bad return value type `%s` for command %s", r->token.chars(), comm->name.chars());
+		
+		r->MustNext (":");
+		
+		// Num args
+		r->MustNumber ();
+		comm->numargs = r->token;
+		
+		r->MustNext (":");
+		
+		// Max args
+		r->MustNumber ();
+		comm->maxargs = r->token;
+		
+		if (comm->maxargs > MAX_MAXARGS)
+			r->ParserError ("maxargs (%d) greater than %d!", comm->maxargs, MAX_MAXARGS);
+		
+		// Argument types
+		int curarg = 0;
+		while (curarg < comm->maxargs) {
+			r->MustNext (":");
+			r->MustNext ();
+			
+			type_e type = GetTypeByName (r->token);
+			if (type == -1)
+				r->ParserError ("bad argument %d type `%s`", curarg, r->token.chars());
+			if (type == TYPE_VOID)
+				r->ParserError ("void is not a valid argument type!");
+			comm->argtypes[curarg] = type;
+			
+			r->MustNext ("(");
+			r->MustNext ();
+			
+			// - 1 because of terminating null character
+			if (r->token.len() > MAX_ARGNAMELEN - 1)
+				r->ParserWarning ("argument name is too long (%d, max is %d)",
+					r->token.len(), MAX_ARGNAMELEN - 1);
+			
+			strncpy (comm->argnames[curarg], r->token.chars(), MAX_ARGNAMELEN);
+			comm->argnames[curarg][MAX_ARGNAMELEN-1] = 0;
+			
+			// If this is an optional parameter, we need the default value.
+			if (curarg >= comm->numargs) {
+				r->MustNext ("=");
+				switch (type) {
+				case TYPE_INT:
+				case TYPE_BOOL:
+					r->MustNumber();
+					break;
+				case TYPE_STRING:
+					r->MustString();
+					break;
+				case TYPE_UNKNOWN:
+				case TYPE_VOID:
+					break;
+				}
+				
+				comm->defvals[curarg] = r->token;
+			}
+			
+			r->MustNext (")");
+			curarg++;
+		}
+		
+		if (!g_CommDef)
+			g_CommDef = comm;
+		
+		if (!curdef) {
+			curdef = comm;
+		} else {
+			curdef->next = comm;
+			curdef = comm;
+		}
+		numCommDefs++;
+	}
+	
+	if (!numCommDefs)
+		r->ParserError ("no commands defined!\n");
+	
+	r->CloseFile ();
+	delete r;
+	printf ("%d command definitions read.\n", numCommDefs);
+}
+
+// ============================================================================
+// Finds a command by name
+CommandDef* FindCommand (str fname) {
+	CommandDef* comm;
+	ITERATE_COMMANDS (comm) {
+		if (!fname.icompare (comm->name))
+			return comm;
+	}
+	
+	return NULL;
+}
+
+// ============================================================================
+// Returns the prototype of the command
+str GetCommandPrototype (CommandDef* comm) {
+	str text;
+	text += GetTypeName (comm->returnvalue);
+	text += ' ';
+	text += comm->name;
+	text += '(';
+	
+	bool hasOptionalArguments = false;
+	for (int i = 0; i < comm->maxargs; i++) {
+		if (i == comm->numargs) {
+			hasOptionalArguments = true;
+			text += '[';
+		}
+		
+		if (i)
+			text += ", ";
+		
+		text += GetTypeName (comm->argtypes[i]);
+		text += ' ';
+		text += comm->argnames[i];
+		
+		if (i >= comm->numargs) {
+			text += '=';
+			
+			bool isString = comm->argtypes[i] == TYPE_STRING;
+			if (isString) text += '"';
+			
+			char defvalstring[8];
+			sprintf (defvalstring, "%d", comm->defvals[i]);
+			text += defvalstring;
+			
+			if (isString) text += '"';
+		}
+	}
+	
+	if (hasOptionalArguments)
+		text += ']';
+	text += ')';
+	return text;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/commands.h	Fri Jan 10 16:11:49 2014 +0200
@@ -0,0 +1,75 @@
+/*
+ *	botc source code
+ *	Copyright (C) 2012 Santeri `Dusk` Piippo
+ *	All rights reserved.
+ *	
+ *	Redistribution and use in source and binary forms, with or without
+ *	modification, are permitted provided that the following conditions are met:
+ *	
+ *	1. Redistributions of source code must retain the above copyright notice,
+ *	   this list of conditions and the following disclaimer.
+ *	2. Redistributions in binary form must reproduce the above copyright notice,
+ *	   this list of conditions and the following disclaimer in the documentation
+ *	   and/or other materials provided with the distribution.
+ *	3. Neither the name of the developer nor the names of its contributors may
+ *	   be used to endorse or promote products derived from this software without
+ *	   specific prior written permission.
+ *	4. Redistributions in any form must be accompanied by information on how to
+ *	   obtain complete source code for the software and any accompanying
+ *	   software that uses the software. The source code must either be included
+ *	   in the distribution or be available for no more than the cost of
+ *	   distribution plus a nominal fee, and must be freely redistributable
+ *	   under reasonable conditions. For an executable file, complete source
+ *	   code means the source code for all modules it contains. It does not
+ *	   include source code for modules or files that typically accompany the
+ *	   major components of the operating system on which the executable file
+ *	   runs.
+ *	
+ *	THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ *	AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ *	IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ *	ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ *	LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *	CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ *	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ *	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ *	POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef __COMMANDS_H__
+#define __COMMANDS_H__
+
+#define MAX_MAXARGS 8
+#define MAX_ARGNAMELEN 16
+
+#include "common.h"
+#include "str.h"
+#include "botcommands.h"
+
+#define ITERATE_COMMANDS(comm) \
+	for (comm = g_CommDef; comm->next != NULL; comm = comm->next)
+
+struct CommandDef {
+	str name;
+	int number;
+	int numargs;
+	int maxargs;
+	type_e returnvalue;
+	type_e argtypes[MAX_MAXARGS];
+	char argnames[MAX_MAXARGS][MAX_ARGNAMELEN];
+	int defvals[MAX_MAXARGS];
+	CommandDef* next;
+};
+
+void ReadCommands ();
+CommandDef* FindCommand (str a);
+str GetCommandPrototype (CommandDef* comm);
+
+#ifndef __COMMANDS_CXX__
+extern
+#endif
+CommandDef* g_CommDef;
+
+#endif // __COMMANDS_H__
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/common.h	Fri Jan 10 16:11:49 2014 +0200
@@ -0,0 +1,186 @@
+/*
+ *	botc source code
+ *	Copyright (C) 2012 Santeri `Dusk` Piippo
+ *	All rights reserved.
+ *	
+ *	Redistribution and use in source and binary forms, with or without
+ *	modification, are permitted provided that the following conditions are met:
+ *	
+ *	1. Redistributions of source code must retain the above copyright notice,
+ *	   this list of conditions and the following disclaimer.
+ *	2. Redistributions in binary form must reproduce the above copyright notice,
+ *	   this list of conditions and the following disclaimer in the documentation
+ *	   and/or other materials provided with the distribution.
+ *	3. Neither the name of the developer nor the names of its contributors may
+ *	   be used to endorse or promote products derived from this software without
+ *	   specific prior written permission.
+ *	4. Redistributions in any form must be accompanied by information on how to
+ *	   obtain complete source code for the software and any accompanying
+ *	   software that uses the software. The source code must either be included
+ *	   in the distribution or be available for no more than the cost of
+ *	   distribution plus a nominal fee, and must be freely redistributable
+ *	   under reasonable conditions. For an executable file, complete source
+ *	   code means the source code for all modules it contains. It does not
+ *	   include source code for modules or files that typically accompany the
+ *	   major components of the operating system on which the executable file
+ *	   runs.
+ *	
+ *	THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ *	AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ *	IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ *	ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ *	LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *	CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ *	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ *	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ *	POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef __COMMON_H__
+#define __COMMON_H__
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include "bots.h"
+#include "str.h"
+
+// Application name and version
+#define APPNAME "botc"
+#define VERSION_MAJOR 0
+#define VERSION_MINOR 999
+
+// Use a macro for Write so we can get the function name
+// This can be pretty crucial in debugging.
+#ifdef __GNUC__
+#define Write(STUFF) DoWrite (__PRETTY_FUNCTION__, STUFF)
+#else
+#define Write(STUFF) DoWrite (__func__, STUFF)
+#endif
+
+// On Windows, files are case-insensitive
+#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32)) && !defined(__CYGWIN__)
+	#define FILE_CASEINSENSITIVE
+#endif
+
+// Parser mode: where is the parser at?
+enum parsermode_e {
+	MODE_TOPLEVEL,	// at top level
+	MODE_EVENT,		// inside event definition
+	MODE_MAINLOOP,	// inside mainloop
+	MODE_ONENTER,	// inside onenter
+	MODE_ONEXIT,	// inside onexit
+};
+
+enum type_e {
+	TYPE_UNKNOWN = 0,
+	TYPE_VOID,
+	TYPE_INT,
+	TYPE_STRING,
+	TYPE_BOOL,
+};
+
+#define CHECK_FILE(pointer,path,action) \
+	if (!pointer) { \
+		error ("couldn't open %s for %s!\n", (char*)path, action); \
+		exit (1); \
+	}
+
+// Shortcut for formatting
+#define PERFORM_FORMAT(in, out) \
+	va_list v; \
+	va_start (v, in); \
+	char* out = vdynformat (in, v, 256); \
+	va_end (v);
+
+// Plural expression
+#define PLURAL(n) (n != 1) ? "s" : ""
+
+// Shortcut for zeroing something
+#define ZERO(obj) memset (&obj, 0, sizeof (obj));
+
+void error (const char* text, ...);
+char* ObjectFileName (str s);
+bool fexists (char* path);
+type_e GetTypeByName (str token);
+str GetTypeName (type_e type);
+
+// Make the parser's variables globally available
+extern int g_NumStates;
+extern int g_NumEvents;
+extern parsermode_e g_CurMode;
+extern str g_CurState;
+
+#define neurosphere if (g_Neurosphere)
+#define twice for (int repeat_token = 0; repeat_token < 2; repeat_token++)
+
+#ifndef __GNUC__
+#define __attribute__(X)
+#endif
+#define deprecated __attribute__ ((deprecated))
+
+// Power function
+template<class T> T pow (T a, unsigned int b) {
+	if (!b)
+		return 1;
+	
+	T r = a;
+	while (b > 1) {
+		b--;
+		r = r * a;
+	}
+	
+	return r;
+}
+
+// Whitespace check
+inline bool IsCharWhitespace (char c) {
+	return (c <= 32 || c == 127 || c == 255);
+}
+
+// Byte datatype
+typedef int32_t word;
+typedef unsigned char byte;
+
+// Keywords
+#ifndef __MAIN_CXX__
+extern const char** g_Keywords;
+#endif
+
+bool IsKeyword (str s);
+unsigned int NumKeywords ();
+
+// Script mark and reference
+struct ScriptMark {
+	str name;
+	size_t pos;
+};
+
+struct ScriptMarkReference {
+	unsigned int num;
+	size_t pos;
+};
+
+// ====================================================================
+// Generic union
+template <class T> union union_t {
+	T val;
+	byte b[sizeof (T)];
+	char c[sizeof (T)];
+	double d;
+	float f;
+	int i;
+	word w;
+};
+
+// ====================================================================
+// Finds a byte in the given value.
+template <class T> inline unsigned char GetByteIndex (T a, unsigned int b) {
+	union_t<T> uni;
+	uni.val = a;
+	return uni.b[b];
+}
+
+#endif // __COMMON_H__
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/databuffer.h	Fri Jan 10 16:11:49 2014 +0200
@@ -0,0 +1,303 @@
+/*
+ *	botc source code
+ *	Copyright (C) 2012 Santeri `Dusk` Piippo
+ *	All rights reserved.
+ *	
+ *	Redistribution and use in source and binary forms, with or without
+ *	modification, are permitted provided that the following conditions are met:
+ *	
+ *	1. Redistributions of source code must retain the above copyright notice,
+ *	   this list of conditions and the following disclaimer.
+ *	2. Redistributions in binary form must reproduce the above copyright notice,
+ *	   this list of conditions and the following disclaimer in the documentation
+ *	   and/or other materials provided with the distribution.
+ *	3. Neither the name of the developer nor the names of its contributors may
+ *	   be used to endorse or promote products derived from this software without
+ *	   specific prior written permission.
+ *	4. Redistributions in any form must be accompanied by information on how to
+ *	   obtain complete source code for the software and any accompanying
+ *	   software that uses the software. The source code must either be included
+ *	   in the distribution or be available for no more than the cost of
+ *	   distribution plus a nominal fee, and must be freely redistributable
+ *	   under reasonable conditions. For an executable file, complete source
+ *	   code means the source code for all modules it contains. It does not
+ *	   include source code for modules or files that typically accompany the
+ *	   major components of the operating system on which the executable file
+ *	   runs.
+ *	
+ *	THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ *	AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ *	IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ *	ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ *	LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *	CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ *	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ *	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ *	POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef  __DATABUFFER_H__
+#define __DATABUFFER_H__
+#include <stdio.h>
+#include <string.h>
+#include "common.h"
+#include "stringtable.h"
+
+#define MAX_MARKS 512
+
+extern int g_NextMark;
+
+// ============================================================================
+// DataBuffer: A dynamic data buffer.
+class DataBuffer {
+public:
+	// The actual buffer
+	byte* buffer;
+	
+	// Allocated size of the buffer
+	unsigned int allocsize;
+	
+	// Written size of the buffer
+	unsigned int writesize;
+	
+	// Marks and references
+	ScriptMark* marks[MAX_MARKS];
+	ScriptMarkReference* refs[MAX_MARKS];
+	
+	// ====================================================================
+	// METHODS
+	
+	// ====================================================================
+	// Constructor
+	DataBuffer (unsigned int size=128) {
+		writesize = 0;
+		
+		buffer = new unsigned char[size];
+		allocsize = size;
+		
+		// Clear the marks table out
+		for (unsigned int u = 0; u < MAX_MARKS; u++) {
+			marks[u] = NULL;
+			refs[u] = NULL;
+		}
+	}
+	
+	// ====================================================================
+	~DataBuffer () {
+		delete buffer;
+		
+		// Delete any marks and references
+		for (unsigned int u = 0; u < MAX_MARKS; u++) {
+			if (marks[u])
+				delete marks[u];
+			
+			if (refs[u])
+				delete refs[u];
+		}
+	}
+	
+	// ====================================================================
+	// Write stuff to the buffer
+	template<class T> void DoWrite (const char* func, T stuff) {
+		// printf ("DoWrite: called from %s\n", func);
+		if (writesize + sizeof (T) >= allocsize) {
+			// We don't have enough space in the buffer to write
+			// the stuff - thus resize. First, store the old
+			// buffer temporarily:
+			char* copy = new char[allocsize];
+			memcpy (copy, buffer, allocsize);
+			
+			// Remake the buffer with the new size. Have enough space
+			// for the stuff we're going to write, as well as a bit
+			// of leeway so we don't have to resize immediately again.
+			size_t newsize = allocsize + sizeof (T) + 128;
+			
+			delete buffer;
+			buffer = new unsigned char[newsize];
+			allocsize = newsize;
+			
+			// Now, copy the stuff back.
+			memcpy (buffer, copy, allocsize);
+			delete copy;
+		}
+		
+		// Buffer is now guaranteed to have enough space.
+		// Write the stuff one byte at a time.
+		union_t<T> uni;
+		uni.val = stuff;
+		for (unsigned int x = 0; x < sizeof (T); x++) {
+			if (writesize >= allocsize) // should NEVER happen because resizing is done above
+				error ("DataBuffer: written size exceeds allocated size!\n");
+			
+			buffer[writesize] = uni.b[x];
+			writesize++;
+		}
+	}
+	
+	// ====================================================================
+	// Merge another data buffer into this one.
+	void Merge (DataBuffer* other) {
+		if (!other)
+			return;
+		int oldsize = writesize;
+		
+		for (unsigned int x = 0; x < other->writesize; x++)
+			Write (*(other->buffer+x));
+		
+		// Merge its marks and references
+		unsigned int u = 0;
+		for (u = 0; u < MAX_MARKS; u++) {
+			if (other->marks[u]) {
+				// Merge the mark and offset its position.
+				if (marks[u])
+					error ("DataBuffer: duplicate mark %d!\n");
+				
+				marks[u] = other->marks[u];
+				marks[u]->pos += oldsize;
+				
+				// The original mark becomes NULL so that the deconstructor
+				// will not delete it prematurely. (should it delete any
+				// marks in the first place since there is no such thing
+				// as at temporary mark?)
+				other->marks[u] = NULL;
+			}
+			
+			if (other->refs[u]) {
+				// Same for references
+				// TODO: add a g_NextRef system like here, akin to marks!
+				unsigned int r = AddMarkReference (other->refs[u]->num, false);
+				refs[r]->pos = other->refs[u]->pos + oldsize;
+			}
+		}
+		
+		delete other;
+	}
+	
+	// Clones this databuffer to a new one and returns it.
+	DataBuffer* Clone () {
+		DataBuffer* other = new DataBuffer;
+		for (unsigned int x = 0; x < writesize; x++)
+			other->Write (*(buffer+x));
+		return other;
+	}
+	
+	// ====================================================================
+	// Adds a mark to the buffer. A mark is a "pointer" to a particular
+	// position in the bytecode. The actual permanent position cannot
+	// be predicted in any way or form, thus these things will be used
+	// to "mark" a position like that for future use.
+	unsigned int AddMark (str name) {
+		// Find a free slot for the mark
+		unsigned int u = g_NextMark++;
+		
+		if (marks[u])
+			error ("DataBuffer: attempted to re-create mark %u!\n", u);
+		
+		if (u >= MAX_MARKS)
+			error ("mark quota exceeded, all labels, if-structs and loops add marks\n");
+		
+		ScriptMark* m = new ScriptMark;
+		m->name = name;
+		m->pos = writesize;
+		marks[u] = m;
+		return u;
+	}
+	
+	// ====================================================================
+	// A ref is another "mark" that references a mark. When the bytecode
+	// is written to file, they are changed into their marks' current
+	// positions. Marks themselves are never written to files, only refs are
+	unsigned int AddMarkReference (unsigned int marknum, bool placeholder = true) {
+		unsigned int u;
+		for (u = 0; u < MAX_MARKS; u++)
+			if (!refs[u])
+				break;
+		
+		if (u == MAX_MARKS)
+			error ("mark reference quota exceeded, all goto-statements, if-structs and loops add refs\n");
+		
+		ScriptMarkReference* r = new ScriptMarkReference;
+		r->num = marknum;
+		r->pos = writesize;
+		refs[u] = r;
+		
+		// Write a dummy placeholder for the reference
+		if (placeholder)
+			Write (1234);
+		
+		return u;
+	}
+	
+	// Delete a mark and all references to it.
+	void DeleteMark (unsigned int marknum) {
+		if (!marks[marknum])
+			return;
+		
+		// Delete the mark
+		delete marks[marknum];
+		marks[marknum] = NULL;
+		
+		// Delete its references
+		for (unsigned int u = 0; u < MAX_MARKS; u++) {
+			if (refs[u]->num == marknum) {
+				delete refs[u];
+				refs[u] = NULL;
+			}
+		}
+	}
+	
+	// Adjusts a mark to the current position
+	void MoveMark (unsigned int mark, int offset = -1) {
+		if (!marks[mark])
+			return;
+		marks[mark]->pos = writesize;
+	}
+	
+	void OffsetMark (unsigned int mark, size_t offset) {
+		if (!marks[mark])
+			return;
+		marks[mark]->pos += offset;
+	}
+	
+	// Dump the buffer (for debugging purposes)
+	void Dump() {
+		for (unsigned int x = 0; x < writesize; x++)
+			printf ("%d. [%d]\n", x, *(buffer+x));
+	}
+	
+	// Count the amount of marks
+	unsigned int CountMarks () {
+		unsigned int count = 0;
+		for (unsigned int u = 0; u < MAX_MARKS; u++)
+			count += !!marks[u];
+		return count;
+	}
+	
+	// Count the amount of refs
+	unsigned int CountReferences () {
+		unsigned int count = 0;
+		for (unsigned int u = 0; u < MAX_MARKS; u++)
+			count += !!refs[u];
+		return count;
+	}
+	
+	// Write a float into the buffer
+	void WriteFloat (str floatstring) {
+		// TODO: Casting float to word causes the decimal to be lost.
+		// Find a way to store the number without such loss.
+		float val = atof (floatstring);
+		Write (DH_PUSHNUMBER);
+		Write (static_cast<word> ((val > 0) ? val : -val));
+		if (val < 0)
+			Write (DH_UNARYMINUS);
+	}
+	
+	void WriteString (str string) {
+		Write (DH_PUSHSTRINGINDEX);
+		Write (PushToStringTable (string));
+	}
+};
+
+#endif // __DATABUFFER_H__
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/events.cxx	Fri Jan 10 16:11:49 2014 +0200
@@ -0,0 +1,112 @@
+/*
+ *	botc source code
+ *	Copyright (C) 2012 Santeri `Dusk` Piippo
+ *	All rights reserved.
+ *	
+ *	Redistribution and use in source and binary forms, with or without
+ *	modification, are permitted provided that the following conditions are met:
+ *	
+ *	1. Redistributions of source code must retain the above copyright notice,
+ *	   this list of conditions and the following disclaimer.
+ *	2. Redistributions in binary form must reproduce the above copyright notice,
+ *	   this list of conditions and the following disclaimer in the documentation
+ *	   and/or other materials provided with the distribution.
+ *	3. Neither the name of the developer nor the names of its contributors may
+ *	   be used to endorse or promote products derived from this software without
+ *	   specific prior written permission.
+ *	4. Redistributions in any form must be accompanied by information on how to
+ *	   obtain complete source code for the software and any accompanying
+ *	   software that uses the software. The source code must either be included
+ *	   in the distribution or be available for no more than the cost of
+ *	   distribution plus a nominal fee, and must be freely redistributable
+ *	   under reasonable conditions. For an executable file, complete source
+ *	   code means the source code for all modules it contains. It does not
+ *	   include source code for modules or files that typically accompany the
+ *	   major components of the operating system on which the executable file
+ *	   runs.
+ *	
+ *	THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ *	AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ *	IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ *	ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ *	LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *	CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ *	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ *	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ *	POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define __EVENTS_CXX__
+#include <stdlib.h>
+#include <stdio.h>
+#include "common.h"
+#include "scriptreader.h"
+#include "str.h"
+#include "events.h"
+
+EventDef* g_EventDef;
+
+// ============================================================================
+// Read event definitions from file
+void ReadEvents () {
+	ScriptReader* r = new ScriptReader ("events.def");
+	g_EventDef = NULL;
+	EventDef* curdef = g_EventDef;
+	unsigned int numEventDefs = 0;
+	while (r->Next()) {
+		EventDef* e = new EventDef;
+		e->name = r->token;
+		e->number = numEventDefs;
+		e->next = NULL;
+		
+		// g_EventDef becomes the first eventdef
+		if (!g_EventDef)
+			g_EventDef = e;
+		
+		if (!curdef) {
+			curdef = e;
+		} else {
+			curdef->next = e;
+			curdef = e;
+		}
+		numEventDefs++;
+	}
+	
+	delete r;
+	printf ("%d event definitions read.\n", numEventDefs);
+}
+
+// ============================================================================
+// Delete event definitions recursively
+void UnlinkEvents (EventDef* e) {
+	if (e->next)
+		UnlinkEvents (e->next);
+	delete e;
+}
+
+// ============================================================================
+// Finds an event definition by index
+EventDef* FindEventByIdx (unsigned int idx) {
+	EventDef* e = g_EventDef;
+	while (idx > 0) {
+		if (!e->next)
+			return NULL;
+		e = e->next;
+		idx--;
+	}
+	return e;
+}
+
+// ============================================================================
+// Finds an event definition by name
+EventDef* FindEventByName (str a) {
+	EventDef* e;
+	for (e = g_EventDef; e->next != NULL; e = e->next) {
+		if (!a.icompare (e->name))
+			return e;
+	}
+	
+	return NULL;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/events.h	Fri Jan 10 16:11:49 2014 +0200
@@ -0,0 +1,57 @@
+/*
+ *	botc source code
+ *	Copyright (C) 2012 Santeri `Dusk` Piippo
+ *	All rights reserved.
+ *	
+ *	Redistribution and use in source and binary forms, with or without
+ *	modification, are permitted provided that the following conditions are met:
+ *	
+ *	1. Redistributions of source code must retain the above copyright notice,
+ *	   this list of conditions and the following disclaimer.
+ *	2. Redistributions in binary form must reproduce the above copyright notice,
+ *	   this list of conditions and the following disclaimer in the documentation
+ *	   and/or other materials provided with the distribution.
+ *	3. Neither the name of the developer nor the names of its contributors may
+ *	   be used to endorse or promote products derived from this software without
+ *	   specific prior written permission.
+ *	4. Redistributions in any form must be accompanied by information on how to
+ *	   obtain complete source code for the software and any accompanying
+ *	   software that uses the software. The source code must either be included
+ *	   in the distribution or be available for no more than the cost of
+ *	   distribution plus a nominal fee, and must be freely redistributable
+ *	   under reasonable conditions. For an executable file, complete source
+ *	   code means the source code for all modules it contains. It does not
+ *	   include source code for modules or files that typically accompany the
+ *	   major components of the operating system on which the executable file
+ *	   runs.
+ *	
+ *	THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ *	AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ *	IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ *	ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ *	LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *	CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ *	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ *	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ *	POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __EVENT_H__
+#define __EVENT_H__
+
+#include "str.h"
+
+struct EventDef {
+	str name;
+	int number;
+	EventDef* next;
+};
+
+void ReadEvents ();
+void UnlinkEvents (EventDef* e);
+EventDef* FindEventByIdx (unsigned int idx);
+EventDef* FindEventByName (str a);
+
+#endif // __EVENT_H__
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/main.cxx	Fri Jan 10 16:11:49 2014 +0200
@@ -0,0 +1,273 @@
+/*
+ *	botc source code
+ *	Copyright (C) 2012 Santeri `Dusk` Piippo
+ *	All rights reserved.
+ *	
+ *	Redistribution and use in source and binary forms, with or without
+ *	modification, are permitted provided that the following conditions are met:
+ *	
+ *	1. Redistributions of source code must retain the above copyright notice,
+ *	   this list of conditions and the following disclaimer.
+ *	2. Redistributions in binary form must reproduce the above copyright notice,
+ *	   this list of conditions and the following disclaimer in the documentation
+ *	   and/or other materials provided with the distribution.
+ *	3. Neither the name of the developer nor the names of its contributors may
+ *	   be used to endorse or promote products derived from this software without
+ *	   specific prior written permission.
+ *	4. Redistributions in any form must be accompanied by information on how to
+ *	   obtain complete source code for the software and any accompanying
+ *	   software that uses the software. The source code must either be included
+ *	   in the distribution or be available for no more than the cost of
+ *	   distribution plus a nominal fee, and must be freely redistributable
+ *	   under reasonable conditions. For an executable file, complete source
+ *	   code means the source code for all modules it contains. It does not
+ *	   include source code for modules or files that typically accompany the
+ *	   major components of the operating system on which the executable file
+ *	   runs.
+ *	
+ *	THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ *	AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ *	IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ *	ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ *	LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *	CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ *	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ *	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ *	POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define __MAIN_CXX__
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "common.h"
+
+#include "str.h"
+#include "scriptreader.h"
+#include "objwriter.h"
+#include "events.h"
+#include "commands.h"
+#include "stringtable.h"
+#include "variables.h"
+#include "array.h"
+#include "databuffer.h"
+
+#include "bots.h"
+#include "botcommands.h"
+
+// List of keywords
+const char* g_Keywords[] = {
+	"bool",
+	"break",
+	"case",
+	"continue",
+	"const",
+	"default",
+	"do",
+	"else",
+	"event",
+	"for",
+	"goto",
+	"if",
+	"int",
+	"mainloop",
+	"onenter",
+	"onexit",
+	"state",
+	"switch",
+	"str"
+	"void",
+	"while",
+	
+	// These ones aren't implemented yet but I plan to do so, thus they are
+	// reserved. Also serves as a to-do list of sorts for me. >:F
+	"enum", // Would enum actually be useful? I think so.
+	"func", // Would function support need external support from zandronum?
+	"return",
+};
+
+// databuffer global variable
+int g_NextMark = 0;
+
+int main (int argc, char** argv) {
+	// Intepret command-line parameters:
+	// -l: list commands
+	// I guess there should be a better way to do this.
+	if (argc == 2 && !strcmp (argv[1], "-l")) {
+		ReadCommands ();
+		printf ("Begin list of commands:\n");
+		printf ("------------------------------------------------------\n");
+		
+		CommandDef* comm;
+		ITERATE_COMMANDS (comm)
+			printf ("%s\n", GetCommandPrototype (comm).chars());
+		
+		printf ("------------------------------------------------------\n");
+		printf ("End of command list\n");
+		exit (0);
+	}
+	
+	// Print header
+	str header;
+	str headerline = "-=";
+	header.appendformat ("%s version %d.%d", APPNAME, VERSION_MAJOR, VERSION_MINOR);
+	
+	headerline *= (header.len() / 2) - 1;
+	headerline += '-';
+	printf ("%s\n%s\n", header.chars(), headerline.chars());
+	
+	if (argc < 2) {
+		fprintf (stderr, "usage: %s <infile> [outfile] # compiles botscript\n", argv[0]);
+		fprintf (stderr, "       %s -l                 # lists commands\n", argv[0]);
+		exit (1);
+	}
+	
+	// A word should always be exactly 4 bytes. The above list command
+	// doesn't need it, but the rest of the program does.
+	if (sizeof (word) != 4)
+		error ("%s expects a word (uint32_t) to be 4 bytes in size, is %d\n",
+			APPNAME, sizeof (word));
+	
+	str outfile;
+	if (argc < 3)
+		outfile = ObjectFileName (argv[1]);
+	else
+		outfile = argv[2];
+	
+	// If we'd end up writing into an existing file,
+	// ask the user if we want to overwrite it
+	if (fexists (outfile)) {
+		// Additional warning if the paths are the same
+		str warning;
+#ifdef FILE_CASEINSENSITIVE
+		if (!outfile.icompare (argv[1]))
+#else
+		if (!outfile.compare (argv[1]))
+#endif
+		{
+			warning = "\nWARNING: Output file is the same as the input file. ";
+			warning += "Answering yes here will destroy the source!\n";
+			warning += "Continue nevertheless?";
+		}
+		printf ("output file `%s` already exists! overwrite?%s (y/n) ", outfile.chars(), warning.chars());
+		
+		char ans;
+		fgets (&ans, 2, stdin);
+		if (ans != 'y') {
+			printf ("abort\n");
+			exit (1);
+		}
+	}
+	
+	// Read definitions
+	printf ("Reading definitions...\n");
+	ReadEvents ();
+	ReadCommands ();
+	
+	// Init stuff
+	InitStringTable ();
+	
+	// Prepare reader and writer
+	ScriptReader* r = new ScriptReader (argv[1]);
+	ObjWriter* w = new ObjWriter (outfile);
+	
+	// We're set, begin parsing :)
+	printf ("Parsing script...\n");
+	r->ParseBotScript (w);
+	printf ("Script parsed successfully.\n");
+	
+	// Parse done, print statistics and write to file
+	unsigned int globalcount = g_GlobalVariables.size();
+	unsigned int stringcount = CountStringTable ();
+	int NumMarks = w->MainBuffer->CountMarks ();
+	int NumRefs = w->MainBuffer->CountReferences ();
+	printf ("%u / %u strings written\n", stringcount, MAX_LIST_STRINGS);
+	printf ("%u / %u global variables\n", globalcount, MAX_SCRIPT_VARIABLES);
+	printf ("%d / %d bytecode marks\n", NumMarks, MAX_MARKS);
+	printf ("%d / %d bytecode references\n", NumRefs, MAX_MARKS);
+	printf ("%d / %d events\n", g_NumEvents, MAX_NUM_EVENTS);
+	printf ("%d state%s\n", g_NumStates, PLURAL (g_NumStates));
+	
+	w->WriteToFile ();
+	
+	// Clear out the junk
+	delete r;
+	delete w;
+	
+	// Done!
+	exit (0);
+}
+
+// ============================================================================
+// Utility functions
+
+// ============================================================================
+// Does the given file exist?
+bool fexists (char* path) {
+	if (FILE* test = fopen (path, "r")) {
+		fclose (test);
+		return true;
+	}
+	return false;
+}
+
+// ============================================================================
+// Generic error
+void error (const char* text, ...) {
+	PERFORM_FORMAT (text, c);
+	fprintf (stderr, "error: %s", c);
+	exit (1);
+}
+
+// ============================================================================
+// Mutates given filename to an object filename
+char* ObjectFileName (str s) {
+	// Locate the extension and chop it out
+	unsigned int extdot = s.last (".");
+	if (extdot >= s.len()-4)
+		s -= (s.len() - extdot);
+	
+	s += ".o";
+	return s.chars();
+}
+
+// ============================================================================
+// Is the given argument a reserved keyword?
+bool IsKeyword (str s) {
+	for (unsigned int u = 0; u < NumKeywords (); u++)
+		if (!s.icompare (g_Keywords[u]))
+			return true;
+	return false;
+}
+
+unsigned int NumKeywords () {
+	return sizeof (g_Keywords) / sizeof (const char*);
+}
+
+// ============================================================================
+type_e GetTypeByName (str t) {
+	t = t.tolower();
+	return	(t == "int") ? TYPE_INT :
+			(t == "str") ? TYPE_STRING :
+			(t == "void") ? TYPE_VOID :
+			(t == "bool") ? TYPE_BOOL :
+			TYPE_UNKNOWN;
+}
+
+
+// ============================================================================
+// Inverse operation - type name by value
+str GetTypeName (type_e type) {
+	switch (type) {
+	case TYPE_INT: return "int"; break;
+	case TYPE_STRING: return "str"; break;
+	case TYPE_VOID: return "void"; break;
+	case TYPE_BOOL: return "bool"; break;
+	case TYPE_UNKNOWN: return "???"; break;
+	}
+	
+	return "";
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/objwriter.cxx	Fri Jan 10 16:11:49 2014 +0200
@@ -0,0 +1,193 @@
+/*
+ *	botc source code
+ *	Copyright (C) 2012 Santeri `Dusk` Piippo
+ *	All rights reserved.
+ *	
+ *	Redistribution and use in source and binary forms, with or without
+ *	modification, are permitted provided that the following conditions are met:
+ *	
+ *	1. Redistributions of source code must retain the above copyright notice,
+ *	   this list of conditions and the following disclaimer.
+ *	2. Redistributions in binary form must reproduce the above copyright notice,
+ *	   this list of conditions and the following disclaimer in the documentation
+ *	   and/or other materials provided with the distribution.
+ *	3. Neither the name of the developer nor the names of its contributors may
+ *	   be used to endorse or promote products derived from this software without
+ *	   specific prior written permission.
+ *	4. Redistributions in any form must be accompanied by information on how to
+ *	   obtain complete source code for the software and any accompanying
+ *	   software that uses the software. The source code must either be included
+ *	   in the distribution or be available for no more than the cost of
+ *	   distribution plus a nominal fee, and must be freely redistributable
+ *	   under reasonable conditions. For an executable file, complete source
+ *	   code means the source code for all modules it contains. It does not
+ *	   include source code for modules or files that typically accompany the
+ *	   major components of the operating system on which the executable file
+ *	   runs.
+ *	
+ *	THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ *	AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ *	IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ *	ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ *	LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *	CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ *	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ *	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ *	POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define __OBJWRITER_CXX__
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "common.h"
+#include "str.h"
+#include "objwriter.h"
+#include "databuffer.h"
+#include "stringtable.h"
+
+#include "bots.h"
+
+extern bool g_GotMainLoop;
+
+ObjWriter::ObjWriter (str path) {
+	MainBuffer = new DataBuffer;
+	MainLoopBuffer = new DataBuffer;
+	OnEnterBuffer = new DataBuffer;
+	SwitchBuffer = NULL; // created on demand
+	numWrittenBytes = 0;
+	numWrittenReferences = 0;
+	filepath = path;
+}
+
+void ObjWriter::WriteString (char* s) {
+	Write (strlen (s));
+	for (unsigned int u = 0; u < strlen (s); u++)
+		Write ((s)[u]);
+}
+
+void ObjWriter::WriteString (const char* s) {
+	WriteString (const_cast<char*> (s));
+}
+
+void ObjWriter::WriteString (str s) {
+	WriteString (s.chars());
+}
+
+void ObjWriter::WriteBuffer (DataBuffer* buf) {
+	GetCurrentBuffer()->Merge (buf);
+}
+
+void ObjWriter::WriteBuffers () {
+	// If there was no mainloop defined, write a dummy one now.
+	if (!g_GotMainLoop) {
+		MainLoopBuffer->Write (DH_MAINLOOP);
+		MainLoopBuffer->Write (DH_ENDMAINLOOP);
+	}
+	
+	// Write the onenter and mainloop buffers, IN THAT ORDER
+	for (int i = 0; i < 2; i++) {
+		DataBuffer** buf = (!i) ? &OnEnterBuffer : &MainLoopBuffer;
+		WriteBuffer (*buf);
+		
+		// Clear the buffer afterwards for potential next state
+		*buf = new DataBuffer;
+	}
+	
+	// Next state definitely has no mainloop yet
+	g_GotMainLoop = false;
+}
+
+// Write string table
+void ObjWriter::WriteStringTable () {
+	unsigned int stringcount = CountStringTable ();
+	if (!stringcount)
+		return;
+	
+	// Write header
+	Write (DH_STRINGLIST);
+	Write (stringcount);
+	
+	// Write all strings
+	for (unsigned int a = 0; a < stringcount; a++)
+		WriteString (g_StringTable[a]);
+}
+
+// Write main buffer to file
+void ObjWriter::WriteToFile () {
+	fp = fopen (filepath, "w");
+	CHECK_FILE (fp, filepath, "writing");
+	
+	// First, resolve references
+	numWrittenReferences = 0;
+	for (unsigned int u = 0; u < MAX_MARKS; u++) {
+		ScriptMarkReference* ref = MainBuffer->refs[u];
+		if (!ref)
+			continue;
+		
+		// Substitute the placeholder with the mark position
+		union_t<word> uni;
+		uni.val = static_cast<word> (MainBuffer->marks[ref->num]->pos);
+		for (unsigned int v = 0; v < sizeof (word); v++)
+			memset (MainBuffer->buffer + ref->pos + v, uni.b[v], 1);
+		
+		/*
+		printf ("reference %u at %d resolved to %u at %d\n",
+			u, ref->pos, ref->num, MainBuffer->marks[ref->num]->pos);
+		*/
+		numWrittenReferences++;
+	}
+	
+	// Then, dump the main buffer to the file
+	for (unsigned int x = 0; x < MainBuffer->writesize; x++)
+		WriteDataToFile<byte> (*(MainBuffer->buffer+x));
+	
+	printf ("-- %u byte%s written to %s\n", numWrittenBytes, PLURAL (numWrittenBytes), filepath.chars());
+	fclose (fp);
+}
+
+DataBuffer* ObjWriter::GetCurrentBuffer() {
+	return	SwitchBuffer ? SwitchBuffer :
+		(g_CurMode == MODE_MAINLOOP) ? MainLoopBuffer :
+		(g_CurMode == MODE_ONENTER) ? OnEnterBuffer :
+		MainBuffer;
+}
+
+ScriptMark* g_ScriptMark = NULL;
+
+// Adds a mark
+unsigned int ObjWriter::AddMark (str name) {
+	return GetCurrentBuffer()->AddMark (name);
+}
+
+// Adds a reference
+unsigned int ObjWriter::AddReference (unsigned int mark) {
+	DataBuffer* b = GetCurrentBuffer();
+	return b->AddMarkReference (mark);
+}
+
+// Finds a mark
+unsigned int ObjWriter::FindMark (str name) {
+	DataBuffer* b = GetCurrentBuffer();
+	for (unsigned int u = 0; u < MAX_MARKS; u++) {
+		if (b->marks[u] && !b->marks[u]->name.icompare (name))
+			return u;
+	}
+	return MAX_MARKS;
+}
+
+// Moves a mark to the current position
+void ObjWriter::MoveMark (unsigned int mark) {
+	GetCurrentBuffer()->MoveMark (mark);
+}
+
+// Deletes a mark
+void ObjWriter::DeleteMark (unsigned int mark) {
+	GetCurrentBuffer()->DeleteMark (mark);
+}
+
+void ObjWriter::OffsetMark (unsigned int mark, int offset) {
+	GetCurrentBuffer()->OffsetMark (mark, offset);
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/objwriter.h	Fri Jan 10 16:11:49 2014 +0200
@@ -0,0 +1,128 @@
+/*
+ *	botc source code
+ *	Copyright (C) 2012 Santeri `Dusk` Piippo
+ *	All rights reserved.
+ *	
+ *	Redistribution and use in source and binary forms, with or without
+ *	modification, are permitted provided that the following conditions are met:
+ *	
+ *	1. Redistributions of source code must retain the above copyright notice,
+ *	   this list of conditions and the following disclaimer.
+ *	2. Redistributions in binary form must reproduce the above copyright notice,
+ *	   this list of conditions and the following disclaimer in the documentation
+ *	   and/or other materials provided with the distribution.
+ *	3. Neither the name of the developer nor the names of its contributors may
+ *	   be used to endorse or promote products derived from this software without
+ *	   specific prior written permission.
+ *	4. Redistributions in any form must be accompanied by information on how to
+ *	   obtain complete source code for the software and any accompanying
+ *	   software that uses the software. The source code must either be included
+ *	   in the distribution or be available for no more than the cost of
+ *	   distribution plus a nominal fee, and must be freely redistributable
+ *	   under reasonable conditions. For an executable file, complete source
+ *	   code means the source code for all modules it contains. It does not
+ *	   include source code for modules or files that typically accompany the
+ *	   major components of the operating system on which the executable file
+ *	   runs.
+ *	
+ *	THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ *	AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ *	IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ *	ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ *	LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *	CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ *	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ *	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ *	POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __OBJWRITER_H__
+#define __OBJWRITER_H__
+
+#include <stdio.h>
+#include <typeinfo>
+#include <string.h>
+#include "common.h"
+#include "str.h"
+#include "databuffer.h"
+
+class ObjWriter {
+public:
+	// ====================================================================
+	// MEMBERS
+	
+	// Pointer to the file we're writing to
+	FILE* fp;
+	
+	// Path to the file we're writing to
+	str filepath;
+	
+	// The main buffer - the contents of this is what we
+	// write to file after parsing is complete
+	DataBuffer* MainBuffer;
+	
+	// onenter buffer - the contents of the onenter{} block
+	// is buffered here and is merged further at the end of state
+	DataBuffer* OnEnterBuffer;
+	
+	// Mainloop buffer - the contents of the mainloop{} block
+	// is buffered here and is merged further at the end of state
+	DataBuffer* MainLoopBuffer;
+	
+	// Switch buffer - switch case data is recorded to this
+	// buffer initially, instead of into main buffer.
+	DataBuffer* SwitchBuffer;
+	
+	// How many bytes have we written to file?
+	unsigned int numWrittenBytes;
+	
+	// How many references did we resolve in the main buffer?
+	unsigned int numWrittenReferences;
+	
+	// ====================================================================
+	// METHODS
+	ObjWriter (str path);
+	void WriteString (char* s);
+	void WriteString (const char* s);
+	void WriteString (str s);
+	void WriteBuffer (DataBuffer* buf);
+	void WriteBuffers ();
+	void WriteStringTable ();
+	void WriteToFile ();
+	DataBuffer* GetCurrentBuffer ();
+	
+	unsigned int AddMark (str name);
+	unsigned int FindMark (str name);
+	unsigned int AddReference (unsigned int mark);
+	void MoveMark (unsigned int mark);
+	void OffsetMark (unsigned int mark, int offset);
+	void DeleteMark (unsigned int mark);
+	template <class T> void DoWrite (const char* func, T stuff) {
+		GetCurrentBuffer ()->DoWrite (func, stuff);
+	}
+	
+	// Default to word
+	void DoWrite (const char* func, word stuff) {
+		DoWrite<word> (func, stuff);
+	}
+	
+	void DoWrite (const char* func, byte stuff) {
+		DoWrite<byte> (func, stuff);
+	}
+	
+private:
+	// Write given data to file.
+	template <class T> void WriteDataToFile (T stuff) {
+		// One byte at a time
+		union_t<T> uni;
+		uni.val = stuff;
+		for (unsigned int x = 0; x < sizeof (T); x++) {
+			fwrite (&uni.b[x], 1, 1, fp);
+			numWrittenBytes++;
+		}
+	}
+};
+
+#endif // __OBJWRITER_H__
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/parser.cxx	Fri Jan 10 16:11:49 2014 +0200
@@ -0,0 +1,1203 @@
+/*
+ *	botc source code
+ *	Copyright (C) 2012 Santeri `Dusk` Piippo
+ *	All rights reserved.
+ *	
+ *	Redistribution and use in source and binary forms, with or without
+ *	modification, are permitted provided that the following conditions are met:
+ *	
+ *	1. Redistributions of source code must retain the above copyright notice,
+ *	   this list of conditions and the following disclaimer.
+ *	2. Redistributions in binary form must reproduce the above copyright notice,
+ *	   this list of conditions and the following disclaimer in the documentation
+ *	   and/or other materials provided with the distribution.
+ *	3. Neither the name of the developer nor the names of its contributors may
+ *	   be used to endorse or promote products derived from this software without
+ *	   specific prior written permission.
+ *	4. Redistributions in any form must be accompanied by information on how to
+ *	   obtain complete source code for the software and any accompanying
+ *	   software that uses the software. The source code must either be included
+ *	   in the distribution or be available for no more than the cost of
+ *	   distribution plus a nominal fee, and must be freely redistributable
+ *	   under reasonable conditions. For an executable file, complete source
+ *	   code means the source code for all modules it contains. It does not
+ *	   include source code for modules or files that typically accompany the
+ *	   major components of the operating system on which the executable file
+ *	   runs.
+ *	
+ *	THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ *	AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ *	IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ *	ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ *	LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *	CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ *	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ *	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ *	POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define __PARSER_CXX__
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "common.h"
+#include "str.h"
+#include "objwriter.h"
+#include "scriptreader.h"
+#include "events.h"
+#include "commands.h"
+#include "stringtable.h"
+#include "variables.h"
+#include "array.h"
+
+#define MUST_TOPLEVEL if (g_CurMode != MODE_TOPLEVEL) \
+	ParserError ("%s-statements may only be defined at top level!", token.chars());
+
+#define MUST_NOT_TOPLEVEL if (g_CurMode == MODE_TOPLEVEL) \
+	ParserError ("%s-statements may not be defined at top level!", token.chars());
+
+#define SCOPE(n) scopestack[g_ScopeCursor - n]
+
+int g_NumStates = 0;
+int g_NumEvents = 0;
+parsermode_e g_CurMode = MODE_TOPLEVEL;
+str g_CurState = "";
+bool g_stateSpawnDefined = false;
+bool g_GotMainLoop = false;
+unsigned int g_ScopeCursor = 0;
+DataBuffer* g_IfExpression = NULL;
+bool g_CanElse = false;
+str* g_UndefinedLabels[MAX_MARKS];
+bool g_Neurosphere = false; // neurosphere-compat
+array<constinfo_t> g_ConstInfo;
+
+// ============================================================================
+// Main parser code. Begins read of the script file, checks the syntax of it
+// and writes the data to the object file via ObjWriter - which also takes care
+// of necessary buffering so stuff is written in the correct order.
+void ScriptReader::ParseBotScript (ObjWriter* w) {
+	// Zero the entire block stack first
+	for (int i = 0; i < MAX_SCOPE; i++)
+		ZERO(scopestack[i]);
+	
+	for (int i = 0; i < MAX_MARKS; i++)
+		g_UndefinedLabels[i] = NULL;
+	
+	while (Next()) {
+		// Check if else is potentically valid
+		if (token == "else" && !g_CanElse)
+			ParserError ("else without preceding if");
+		if (token != "else")
+			g_CanElse = false;
+		
+		// ============================================================
+		if (token == "state") {
+			MUST_TOPLEVEL
+			
+			MustString ();
+			
+			// State name must be a word.
+			if (token.first (" ") != token.len())
+				ParserError ("state name must be a single word, got `%s`", token.chars());
+			str statename = token;
+			
+			// stateSpawn is special - it *must* be defined. If we
+			// encountered it, then mark down that we have it.
+			if (-token == "statespawn")
+				g_stateSpawnDefined = true;
+			
+			// Must end in a colon
+			MustNext (":");
+			
+			// Write the previous state's onenter and
+			// mainloop buffers to file now
+			if (g_CurState.len())
+				w->WriteBuffers();
+			
+			w->Write (DH_STATENAME);
+			w->WriteString (statename);
+			w->Write (DH_STATEIDX);
+			w->Write (g_NumStates);
+			
+			g_NumStates++;
+			g_CurState = token;
+			g_GotMainLoop = false;
+			continue;
+		}
+		
+		// ============================================================
+		if (token == "event") {
+			MUST_TOPLEVEL
+			
+			// Event definition
+			MustString ();
+			
+			EventDef* e = FindEventByName (token);
+			if (!e)
+				ParserError ("bad event, got `%s`\n", token.chars());
+			
+			MustNext ("{");
+			
+			g_CurMode = MODE_EVENT;
+			
+			w->Write (DH_EVENT);
+			w->Write (e->number);
+			g_NumEvents++;
+			continue;
+		}
+		
+		// ============================================================
+		if (token == "mainloop") {
+			MUST_TOPLEVEL
+			MustNext ("{");
+			
+			// Mode must be set before dataheader is written here!
+			g_CurMode = MODE_MAINLOOP;
+			w->Write (DH_MAINLOOP);
+			continue;
+		}
+		
+		// ============================================================
+		if (token == "onenter" || token == "onexit") {
+			MUST_TOPLEVEL
+			bool onenter = token == "onenter";
+			MustNext ("{");
+			
+			// Mode must be set before dataheader is written here,
+			// because onenter goes to a separate buffer.
+			g_CurMode = onenter ? MODE_ONENTER : MODE_ONEXIT;
+			w->Write (onenter ? DH_ONENTER : DH_ONEXIT);
+			continue;
+		}
+		
+		// ============================================================
+		if (token == "int" || token == "str" || token == "bool") {
+			// For now, only globals are supported
+			if (g_CurMode != MODE_TOPLEVEL || g_CurState.len())
+				ParserError ("variables must only be global for now");
+			
+			type_e type =	(token == "int") ? TYPE_INT :
+							(token == "str") ? TYPE_STRING :
+							TYPE_BOOL;
+			
+			MustNext ();
+			
+			// Var name must not be a number
+			if (token.isnumber())
+				ParserError ("variable name must not be a number");
+			
+			str varname = token;
+			ScriptVar* var = DeclareGlobalVariable (this, type, varname);
+			
+			if (!var)
+				ParserError ("declaring %s variable %s failed",
+					g_CurState.len() ? "state" : "global", varname.chars());
+			
+			MustNext (";");
+			continue;
+		}
+		
+		// ============================================================
+		// Goto
+		if (token == "goto") {
+			MUST_NOT_TOPLEVEL
+			
+			// Get the name of the label
+			MustNext ();
+			
+			// Find the mark this goto statement points to
+			unsigned int m = w->FindMark (token);
+			
+			// If not set, define it
+			if (m == MAX_MARKS) {
+				m = w->AddMark (token);
+				g_UndefinedLabels[m] = new str (token);
+			}
+			
+			// Add a reference to the mark.
+			w->Write (DH_GOTO);
+			w->AddReference (m);
+			MustNext (";");
+			continue;
+		}
+		
+		// ============================================================
+		// If
+		if (token == "if") {
+			MUST_NOT_TOPLEVEL
+			PushScope ();
+			
+			// Condition
+			MustNext ("(");
+			
+			// Read the expression and write it.
+			MustNext ();
+			DataBuffer* c = ParseExpression (TYPE_INT);
+			w->WriteBuffer (c);
+			
+			MustNext (")");
+			MustNext ("{");
+			
+			// Add a mark - to here temporarily - and add a reference to it.
+			// Upon a closing brace, the mark will be adjusted.
+			unsigned int marknum = w->AddMark ("");
+			
+			// Use DH_IFNOTGOTO - if the expression is not true, we goto the mark
+			// we just defined - and this mark will be at the end of the scope block.
+			w->Write (DH_IFNOTGOTO);
+			w->AddReference (marknum);
+			
+			// Store it
+			SCOPE(0).mark1 = marknum;
+			SCOPE(0).type = SCOPETYPE_IF;
+			continue;
+		}
+		
+		if (token == "else") {
+			MUST_NOT_TOPLEVEL
+			MustNext ("{");
+			
+			// Don't use PushScope as it resets the scope
+			g_ScopeCursor++;
+			if (g_ScopeCursor >= MAX_SCOPE)
+				ParserError ("too deep scope");
+			
+			if (SCOPE(0).type != SCOPETYPE_IF)
+				ParserError ("else without preceding if");
+			
+			// Write down to jump to the end of the else statement
+			// Otherwise we have fall-throughs
+			SCOPE(0).mark2 = w->AddMark ("");
+			
+			// Instruction to jump to the end after if block is complete
+			w->Write (DH_GOTO);
+			w->AddReference (SCOPE(0).mark2);
+			
+			// Move the ifnot mark here and set type to else
+			w->MoveMark (SCOPE(0).mark1);
+			SCOPE(0).type = SCOPETYPE_ELSE;
+			continue;
+		}
+		
+		// ============================================================
+		// While
+		if (token == "while") {
+			MUST_NOT_TOPLEVEL
+			PushScope ();
+			
+			// While loops need two marks - one at the start of the loop and one at the
+			// end. The condition is checked at the very start of the loop, if it fails,
+			// we use goto to skip to the end of the loop. At the end, we loop back to
+			// the beginning with a go-to statement.
+			unsigned int mark1 = w->AddMark (""); // start
+			unsigned int mark2 = w->AddMark (""); // end
+			
+			// Condition
+			MustNext ("(");
+			MustNext ();
+			DataBuffer* expr = ParseExpression (TYPE_INT);
+			MustNext (")");
+			MustNext ("{");
+			
+			// Write condition
+			w->WriteBuffer (expr);
+			
+			// Instruction to go to the end if it fails
+			w->Write (DH_IFNOTGOTO);
+			w->AddReference (mark2);
+			
+			// Store the needed stuff
+			SCOPE(0).mark1 = mark1;
+			SCOPE(0).mark2 = mark2;
+			SCOPE(0).type = SCOPETYPE_WHILE;
+			continue;
+		}
+		
+		// ============================================================
+		// For loop
+		if (token == "for") {
+			MUST_NOT_TOPLEVEL
+			PushScope ();
+			
+			// Initializer
+			MustNext ("(");
+			MustNext ();
+			DataBuffer* init = ParseStatement (w);
+			if (!init)
+				ParserError ("bad statement for initializer of for");
+			
+			MustNext (";");
+			
+			// Condition
+			MustNext ();
+			DataBuffer* cond = ParseExpression (TYPE_INT);
+			if (!cond)
+				ParserError ("bad statement for condition of for");
+			
+			MustNext (";");
+			
+			// Incrementor
+			MustNext ();
+			DataBuffer* incr = ParseStatement (w);
+			if (!incr)
+				ParserError ("bad statement for incrementor of for");
+			
+			MustNext (")");
+			MustNext ("{");
+			
+			// First, write out the initializer
+			w->WriteBuffer (init);
+			
+			// Init two marks
+			int mark1 = w->AddMark ("");
+			int mark2 = w->AddMark ("");
+			
+			// Add the condition
+			w->WriteBuffer (cond);
+			w->Write (DH_IFNOTGOTO);
+			w->AddReference (mark2);
+			
+			// Store the marks and incrementor
+			SCOPE(0).mark1 = mark1;
+			SCOPE(0).mark2 = mark2;
+			SCOPE(0).buffer1 = incr;
+			SCOPE(0).type = SCOPETYPE_FOR;
+			continue;
+		}
+		
+		// ============================================================
+		// Do/while loop
+		if (token == "do") {
+			MUST_NOT_TOPLEVEL
+			PushScope ();
+			MustNext ("{");
+			SCOPE(0).mark1 = w->AddMark ("");
+			SCOPE(0).type = SCOPETYPE_DO;
+			continue;
+		}
+		
+		// ============================================================
+		// Switch
+		if (token == "switch") {
+			/* This goes a bit tricky. switch is structured in the
+			 * bytecode followingly:
+			 * (expression)
+			 * case a: goto casemark1
+			 * case b: goto casemark2
+			 * case c: goto casemark3
+			 * goto mark1 // jump to end if no matches
+			 * casemark1: ...
+			 * casemark2: ...
+			 * casemark3: ...
+			 * mark1: // end mark
+			 */
+			
+			MUST_NOT_TOPLEVEL
+			PushScope ();
+			MustNext ("(");
+			MustNext ();
+			w->WriteBuffer (ParseExpression (TYPE_INT));
+			MustNext (")");
+			MustNext ("{");
+			SCOPE(0).type = SCOPETYPE_SWITCH;
+			SCOPE(0).mark1 = w->AddMark (""); // end mark
+			SCOPE(0).buffer1 = NULL; // default header
+			continue;
+		}
+		
+		// ============================================================
+		if (token == "case") {
+			// case is only allowed inside switch
+			if (SCOPE(0).type != SCOPETYPE_SWITCH)
+				ParserError ("case label outside switch");
+			
+			// Get the literal (Zandronum does not support expressions here)
+			MustNumber ();
+			int num = atoi (token.chars ());
+			MustNext (":");
+			
+			for (int i = 0; i < MAX_CASE; i++)
+				if (SCOPE(0).casenumbers[i] == num)
+					ParserError ("multiple case %d labels in one switch", num);
+			
+			// Write down the expression and case-go-to. This builds
+			// the case tree. The closing event will write the actual
+			// blocks and move the marks appropriately.
+			//	AddSwitchCase will add the reference to the mark
+			// for the case block that this heralds, and takes care
+			// of buffering setup and stuff like that.
+			//	NULL the switch buffer for the case-go-to statement,
+			// we want it all under the switch, not into the case-buffers.
+			w->SwitchBuffer = NULL;
+			w->Write (DH_CASEGOTO);
+			w->Write (num);
+			AddSwitchCase (w, NULL);
+			SCOPE(0).casenumbers[SCOPE(0).casecursor] = num;
+			continue;
+		}
+		
+		if (token == "default") {
+			if (SCOPE(0).type != SCOPETYPE_SWITCH)
+				ParserError ("default label outside switch");
+			
+			if (SCOPE(0).buffer1)
+				ParserError ("multiple default labels in one switch");
+			
+			MustNext (":");
+			
+			// The default header is buffered into buffer1, since
+			// it has to be the last of the case headers
+			//
+			// Since the expression is pushed into the switch
+			// and is only popped when case succeeds, we have
+			// to pop it with DH_DROP manually if we end up in
+			// a default.
+			DataBuffer* b = new DataBuffer;
+			SCOPE(0).buffer1 = b;
+			b->Write (DH_DROP);
+			b->Write (DH_GOTO);
+			AddSwitchCase (w, b);
+			continue;
+		}
+		
+		// ============================================================
+		// Break statement.
+		if (token == "break") {
+			if (!g_ScopeCursor)
+				ParserError ("unexpected `break`");
+			
+			w->Write (DH_GOTO);
+			
+			// switch and if use mark1 for the closing point,
+			// for and while use mark2.
+			switch (SCOPE(0).type) {
+			case SCOPETYPE_IF:
+			case SCOPETYPE_SWITCH:
+				w->AddReference (SCOPE(0).mark1);
+				break;
+			case SCOPETYPE_FOR:
+			case SCOPETYPE_WHILE:
+				w->AddReference (SCOPE(0).mark2);
+				break;
+			default:
+				ParserError ("unexpected `break`");
+				break;
+			}
+			
+			MustNext (";");
+			continue;
+		}
+		
+		// ============================================================
+		// Continue
+		if (token == "continue") {
+			MustNext (";");
+			
+			int curs;
+			bool found = false;
+			
+			// Drop through the scope until we find a loop block
+			for (curs = g_ScopeCursor; curs > 0 && !found; curs--) {
+				switch (scopestack[curs].type) {
+				case SCOPETYPE_FOR:
+				case SCOPETYPE_WHILE:
+				case SCOPETYPE_DO:
+					w->Write (DH_GOTO);
+					w->AddReference (scopestack[curs].mark1);
+					found = true;
+					break;
+				default:
+					break;
+				}
+			}
+			
+			// No loop blocks
+			if (!found)
+				ParserError ("`continue`-statement not inside a loop");
+			
+			continue;
+		}
+		
+		// ============================================================
+		// Label
+		if (PeekNext() == ":") {
+			MUST_NOT_TOPLEVEL
+			
+			// want no conflicts..
+			if (IsKeyword (token))
+				ParserError ("label name `%s` conflicts with keyword\n", token.chars());
+			if (FindCommand (token))
+				ParserError ("label name `%s` conflicts with command name\n", token.chars());
+			if (FindGlobalVariable (token))
+				ParserError ("label name `%s` conflicts with variable\n", token.chars());
+			
+			// See if a mark already exists for this label
+			int mark = -1;
+			for (int i = 0; i < MAX_MARKS; i++) {
+				if (g_UndefinedLabels[i] && *g_UndefinedLabels[i] == token) {
+					mark = i;
+					w->MoveMark (i);
+					
+					// No longer undefinde
+					delete g_UndefinedLabels[i];
+					g_UndefinedLabels[i] = NULL;
+				}
+			}
+			
+			// Not found in unmarked lists, define it now
+			if (mark == -1)
+				w->AddMark (token);
+			
+			MustNext (":");
+			continue;
+		}
+		
+		// ============================================================
+		if (token == "const") {
+			constinfo_t info;
+			
+			// Get the type
+			MustNext ();
+			info.type = GetTypeByName (token);
+			
+			if (info.type == TYPE_UNKNOWN || info.type == TYPE_VOID)
+				ParserError ("unknown type `%s` for constant", (char*)token);
+			
+			MustNext ();
+			info.name = token;
+			
+			MustNext ("=");
+			
+			switch (info.type) {
+			case TYPE_BOOL:
+			case TYPE_INT:
+				MustNumber (false);
+				info.val = token;
+				break;
+			case TYPE_STRING:
+				MustString ();
+				info.val = token;
+				break;
+			case TYPE_UNKNOWN:
+			case TYPE_VOID:
+				break;
+			}
+			
+			g_ConstInfo << info;
+			
+			MustNext (";");
+			continue;
+		}
+		
+		// ============================================================
+		if (token == "}") {
+			// Closing brace
+			
+			// If we're in the block stack, we're descending down from it now
+			if (g_ScopeCursor > 0) {
+				switch (SCOPE(0).type) {
+				case SCOPETYPE_IF:
+					// Adjust the closing mark.
+					w->MoveMark (SCOPE(0).mark1);
+					
+					// We're returning from if, thus else can be next
+					g_CanElse = true;
+					break;
+				case SCOPETYPE_ELSE:
+					// else instead uses mark1 for itself (so if expression
+					// fails, jump to else), mark2 means end of else
+					w->MoveMark (SCOPE(0).mark2);
+					break;
+				case SCOPETYPE_FOR:
+					// Write the incrementor at the end of the loop block
+					w->WriteBuffer (SCOPE(0).buffer1);
+					// fall-thru
+				case SCOPETYPE_WHILE:
+					// Write down the instruction to go back to the start of the loop
+					w->Write (DH_GOTO);
+					w->AddReference (SCOPE(0).mark1);
+					
+					// Move the closing mark here since we're at the end of the while loop
+					w->MoveMark (SCOPE(0).mark2);
+					break;
+				case SCOPETYPE_DO: { 
+					MustNext ("while");
+					MustNext ("(");
+					MustNext ();
+					DataBuffer* expr = ParseExpression (TYPE_INT);
+					MustNext (")");
+					MustNext (";");
+					
+					// If the condition runs true, go back to the start.
+					w->WriteBuffer (expr);
+					w->Write (DH_IFGOTO);
+					w->AddReference (SCOPE(0).mark1);
+					break;
+				}
+				case SCOPETYPE_SWITCH: {
+					// Switch closes. Move down to the record buffer of
+					// the lower block.
+					if (SCOPE(1).casecursor != -1)
+						w->SwitchBuffer = SCOPE(1).casebuffers[SCOPE(1).casecursor];
+					else
+						w->SwitchBuffer = NULL;
+					
+					// If there was a default in the switch, write its header down now.
+					// If not, write instruction to jump to the end of switch after
+					// the headers (thus won't fall-through if no case matched)
+					if (SCOPE(0).buffer1)
+						w->WriteBuffer (SCOPE(0).buffer1);
+					else {
+						w->Write (DH_DROP);
+						w->Write (DH_GOTO);
+						w->AddReference (SCOPE(0).mark1);
+					}
+					
+					// Go through all of the buffers we
+					// recorded down and write them.
+					for (unsigned int u = 0; u < MAX_CASE; u++) {
+						if (!SCOPE(0).casebuffers[u])
+							continue;
+						
+						w->MoveMark (SCOPE(0).casemarks[u]);
+						w->WriteBuffer (SCOPE(0).casebuffers[u]);
+					}
+					
+					// Move the closing mark here
+					w->MoveMark (SCOPE(0).mark1);
+					break;
+				}
+				case SCOPETYPE_UNKNOWN:
+					break;
+				}
+				
+				// Descend down the stack
+				g_ScopeCursor--;
+				continue;
+			}
+			
+			int dataheader =	(g_CurMode == MODE_EVENT) ? DH_ENDEVENT :
+						(g_CurMode == MODE_MAINLOOP) ? DH_ENDMAINLOOP :
+						(g_CurMode == MODE_ONENTER) ? DH_ENDONENTER :
+						(g_CurMode == MODE_ONEXIT) ? DH_ENDONEXIT : -1;
+			
+			if (dataheader == -1)
+				ParserError ("unexpected `}`");
+			
+			// Data header must be written before mode is changed because
+			// onenter and mainloop go into special buffers, and we want
+			// the closing data headers into said buffers too.
+			w->Write (dataheader);
+			g_CurMode = MODE_TOPLEVEL;
+			
+			if (PeekNext() == ";")
+				MustNext (";");
+			continue;
+		}
+		
+		// Check if it's a command
+		CommandDef* comm = FindCommand (token);
+		if (comm) {
+			w->GetCurrentBuffer()->Merge (ParseCommand (comm));
+			MustNext (";");
+			continue;
+		}
+		
+		// ============================================================
+		// If nothing else, parse it as a statement
+		DataBuffer* b = ParseStatement (w);
+		if (!b)
+			ParserError ("unknown token `%s`", token.chars());
+		
+		w->WriteBuffer (b);
+		MustNext (";");
+	}
+	
+	// ===============================================================================
+	// Script file ended. Do some last checks and write the last things to main buffer
+	if (g_CurMode != MODE_TOPLEVEL)
+		ParserError ("script did not end at top level; did you forget a `}`?");
+	
+	// stateSpawn must be defined!
+	if (!g_stateSpawnDefined)
+		ParserError ("script must have a state named `stateSpawn`!");
+	
+	for (int i = 0; i < MAX_MARKS; i++)
+		if (g_UndefinedLabels[i])
+			ParserError ("label `%s` is referenced via `goto` but isn't defined\n", g_UndefinedLabels[i]->chars());
+	
+	// Dump the last state's onenter and mainloop
+	w->WriteBuffers ();
+	
+	// String table
+	w->WriteStringTable ();
+}
+
+// ============================================================================
+// Parses a command call
+DataBuffer* ScriptReader::ParseCommand (CommandDef* comm) {
+	DataBuffer* r = new DataBuffer(64);
+	if (g_CurMode == MODE_TOPLEVEL)
+		ParserError ("command call at top level");
+	
+	MustNext ("(");
+	MustNext ();
+	
+	int curarg = 0;
+	while (1) {
+		if (token == ")") {
+			if (curarg < comm->numargs)
+				ParserError ("too few arguments passed to %s\n\tprototype: %s",
+					comm->name.chars(), GetCommandPrototype (comm).chars());
+			break;
+			curarg++;
+		}
+		
+		if (curarg >= comm->maxargs)
+			ParserError ("too many arguments passed to %s\n\tprototype: %s",
+				comm->name.chars(), GetCommandPrototype (comm).chars());
+		
+		r->Merge (ParseExpression (comm->argtypes[curarg]));
+		MustNext ();
+		
+		if (curarg < comm->numargs - 1) {
+			MustThis (",");
+			MustNext ();
+		} else if (curarg < comm->maxargs - 1) {
+			// Can continue, but can terminate as well.
+			if (token == ")") {
+				curarg++;
+				break;
+			} else {
+				MustThis (",");
+				MustNext ();
+			}
+		}
+		
+		curarg++;
+	}
+	
+	// If the script skipped any optional arguments, fill in defaults.
+	while (curarg < comm->maxargs) {
+		r->Write (DH_PUSHNUMBER);
+		r->Write (comm->defvals[curarg]);
+		curarg++;
+	}
+	
+	r->Write (DH_COMMAND);
+	r->Write (comm->number);
+	r->Write (comm->maxargs);
+	
+	return r;
+}
+
+// ============================================================================
+// Is the given operator an assignment operator?
+static bool IsAssignmentOperator (int oper) {
+	switch (oper) {
+	case OPER_ASSIGNADD:
+	case OPER_ASSIGNSUB:
+	case OPER_ASSIGNMUL:
+	case OPER_ASSIGNDIV:
+	case OPER_ASSIGNMOD:
+	case OPER_ASSIGNLEFTSHIFT:
+	case OPER_ASSIGNRIGHTSHIFT:
+	case OPER_ASSIGN:
+		return true;
+	}
+	return false;
+}
+
+// ============================================================================
+// Finds an operator's corresponding dataheader
+static word DataHeaderByOperator (ScriptVar* var, int oper) {
+	if (IsAssignmentOperator (oper)) {
+		if (!var)
+			error ("operator %d requires left operand to be a variable\n", oper);
+		
+		// TODO: At the moment, vars only are global
+		// OPER_ASSIGNLEFTSHIFT and OPER_ASSIGNRIGHTSHIFT do not
+		// have data headers, instead they are expanded out in
+		// the operator parser
+		switch (oper) {
+		case OPER_ASSIGNADD: return DH_ADDGLOBALVAR;
+		case OPER_ASSIGNSUB: return DH_SUBGLOBALVAR;
+		case OPER_ASSIGNMUL: return DH_MULGLOBALVAR;
+		case OPER_ASSIGNDIV: return DH_DIVGLOBALVAR;
+		case OPER_ASSIGNMOD: return DH_MODGLOBALVAR;
+		case OPER_ASSIGN: return DH_ASSIGNGLOBALVAR;
+		default: error ("bad assignment operator!!\n");
+		}
+	}
+	
+	switch (oper) {
+	case OPER_ADD: return DH_ADD;
+	case OPER_SUBTRACT: return DH_SUBTRACT;
+	case OPER_MULTIPLY: return DH_MULTIPLY;
+	case OPER_DIVIDE: return DH_DIVIDE;
+	case OPER_MODULUS: return DH_MODULUS;
+	case OPER_EQUALS: return DH_EQUALS;
+	case OPER_NOTEQUALS: return DH_NOTEQUALS;
+	case OPER_LESSTHAN: return DH_LESSTHAN;
+	case OPER_GREATERTHAN: return DH_GREATERTHAN;
+	case OPER_LESSTHANEQUALS: return DH_LESSTHANEQUALS;
+	case OPER_GREATERTHANEQUALS: return DH_GREATERTHANEQUALS;
+	case OPER_LEFTSHIFT: return DH_LSHIFT;
+	case OPER_RIGHTSHIFT: return DH_RSHIFT;
+	case OPER_OR: return DH_ORLOGICAL;
+	case OPER_AND: return DH_ANDLOGICAL;
+	case OPER_BITWISEOR: return DH_ORBITWISE;
+	case OPER_BITWISEEOR: return DH_EORBITWISE;
+	case OPER_BITWISEAND: return DH_ANDBITWISE;
+	}
+	
+	error ("DataHeaderByOperator: couldn't find dataheader for operator %d!\n", oper);
+	return 0;
+}
+
+// ============================================================================
+// Parses an expression, potentially recursively
+DataBuffer* ScriptReader::ParseExpression (type_e reqtype) {
+	DataBuffer* retbuf = new DataBuffer (64);
+	
+	// Parse first operand
+	retbuf->Merge (ParseExprValue (reqtype));
+	
+	// Parse any and all operators we get
+	int oper;
+	while ((oper = ParseOperator (true)) != -1) {
+		// We peeked the operator, move forward now
+		Next ();
+		
+		// Can't be an assignement operator, those belong in assignments.
+		if (IsAssignmentOperator (oper))
+			ParserError ("assignment operator inside expression");
+		
+		// Parse the right operand.
+		MustNext ();
+		DataBuffer* rb = ParseExprValue (reqtype);
+		
+		if (oper == OPER_TERNARY) {
+			// Ternary operator requires - naturally - a third operand.
+			MustNext (":");
+			MustNext ();
+			DataBuffer* tb = ParseExprValue (reqtype);
+			
+			// It also is handled differently: there isn't a dataheader for ternary
+			// operator. Instead, we abuse PUSHNUMBER and IFNOTGOTO for this.
+			// Behold, big block of writing madness! :P
+			int mark1 = retbuf->AddMark (""); // start of "else" case
+			int mark2 = retbuf->AddMark (""); // end of expression
+			retbuf->Write (DH_IFNOTGOTO); // if the first operand (condition)
+			retbuf->AddMarkReference (mark1); // didn't eval true, jump into mark1
+			retbuf->Merge (rb); // otherwise, perform second operand (true case)
+			retbuf->Write (DH_GOTO); // afterwards, jump to the end, which is
+			retbuf->AddMarkReference (mark2); // marked by mark2.
+			retbuf->MoveMark (mark1); // move mark1 at the end of the true case
+			retbuf->Merge (tb); // perform third operand (false case)
+			retbuf->MoveMark (mark2); // move the ending mark2 here
+		} else {
+			// Write to buffer
+			retbuf->Merge (rb);
+			retbuf->Write (DataHeaderByOperator (NULL, oper));
+		}
+	}
+	
+	return retbuf;
+}
+
+// ============================================================================
+// Parses an operator string. Returns the operator number code.
+#define ISNEXT(char) (!PeekNext (peek ? 1 : 0) == char)
+int ScriptReader::ParseOperator (bool peek) {
+	str oper;
+	if (peek)
+		oper += PeekNext ();
+	else
+		oper += token;
+	
+	if (-oper == "strlen")
+		return OPER_STRLEN;
+	
+	// Check one-char operators
+	bool equalsnext = ISNEXT ("=");
+	
+	int o =	(oper == "=" && !equalsnext) ? OPER_ASSIGN :
+		(oper == ">" && !equalsnext && !ISNEXT (">")) ? OPER_GREATERTHAN :
+		(oper == "<" && !equalsnext && !ISNEXT ("<")) ? OPER_LESSTHAN :
+		(oper == "&" && !ISNEXT ("&")) ? OPER_BITWISEAND :
+		(oper == "|" && !ISNEXT ("|")) ? OPER_BITWISEOR :
+		(oper == "+" && !equalsnext) ? OPER_ADD :
+		(oper == "-" && !equalsnext) ? OPER_SUBTRACT :
+		(oper == "*" && !equalsnext) ? OPER_MULTIPLY :
+		(oper == "/" && !equalsnext) ? OPER_DIVIDE :
+		(oper == "%" && !equalsnext) ? OPER_MODULUS :
+		(oper == "^") ? OPER_BITWISEEOR :
+		(oper == "?") ? OPER_TERNARY :
+		-1;
+	
+	if (o != -1) {
+		return o;
+	}
+	
+	// Two-char operators
+	oper += PeekNext (peek ? 1 : 0);
+	equalsnext = PeekNext (peek ? 2 : 1) == ("=");
+	
+	o =	(oper == "+=") ? OPER_ASSIGNADD :
+		(oper == "-=") ? OPER_ASSIGNSUB :
+		(oper == "*=") ? OPER_ASSIGNMUL :
+		(oper == "/=") ? OPER_ASSIGNDIV :
+		(oper == "%=") ? OPER_ASSIGNMOD :
+		(oper == "==") ? OPER_EQUALS :
+		(oper == "!=") ? OPER_NOTEQUALS :
+		(oper == ">=") ? OPER_GREATERTHANEQUALS :
+		(oper == "<=") ? OPER_LESSTHANEQUALS :
+		(oper == "&&") ? OPER_AND :
+		(oper == "||") ? OPER_OR :
+		(oper == "<<" && !equalsnext) ? OPER_LEFTSHIFT :
+		(oper == ">>" && !equalsnext) ? OPER_RIGHTSHIFT :
+		-1;
+	
+	if (o != -1) {
+		MustNext ();
+		return o;
+	}
+	
+	// Three-char opers
+	oper += PeekNext (peek ? 2 : 1);
+	o =	oper == "<<=" ? OPER_ASSIGNLEFTSHIFT :
+		oper == ">>=" ? OPER_ASSIGNRIGHTSHIFT :
+		-1;
+	
+	if (o != -1) {
+		MustNext ();
+		MustNext ();
+	}
+	
+	return o;
+}
+
+// ============================================================================
+str ScriptReader::ParseFloat () {
+	MustNumber (true);
+	str floatstring = token;
+	
+	// Go after the decimal point
+	if (PeekNext () == ".") {
+		Next (".");
+		MustNumber (false);
+		floatstring += ".";
+		floatstring += token;
+	}
+	
+	return floatstring;
+}
+
+// ============================================================================
+// Parses a value in the expression and returns the data needed to push
+// it, contained in a data buffer. A value can be either a variable, a command,
+// a literal or an expression.
+DataBuffer* ScriptReader::ParseExprValue (type_e reqtype) {
+	DataBuffer* b = new DataBuffer(16);
+	
+	ScriptVar* g;
+	
+	// Prefixing "!" means negation.
+	bool negate = (token == "!");
+	if (negate) // Jump past the "!"
+		Next ();
+	
+	// Handle strlen
+	if (token == "strlen") {
+		MustNext ("(");
+		MustNext ();
+		
+		// By this token we should get a string constant.
+		constinfo_t* constant = FindConstant (token);
+		if (!constant || constant->type != TYPE_STRING)
+			ParserError ("strlen only works with const str");
+		
+		if (reqtype != TYPE_INT)
+			ParserError ("strlen returns int but %s is expected\n", (char*)GetTypeName (reqtype));
+		
+		b->Write (DH_PUSHNUMBER);
+		b->Write (constant->val.len ());
+		
+		MustNext (")");
+	} else if (token == "(") {
+		// Expression
+		MustNext ();
+		DataBuffer* c = ParseExpression (reqtype);
+		b->Merge (c);
+		MustNext (")");
+	} else if (CommandDef* comm = FindCommand (token)) {
+		delete b;
+		
+		// Command
+		if (reqtype && comm->returnvalue != reqtype)
+			ParserError ("%s returns an incompatible data type", comm->name.chars());
+		b = ParseCommand (comm);
+	} else if (constinfo_t* constant = FindConstant (token)) {
+		// Type check
+		if (reqtype != constant->type)
+			ParserError ("constant `%s` is %s, expression requires %s\n",
+				(char*)constant->name, (char*)GetTypeName (constant->type),
+				(char*)GetTypeName (reqtype));
+		
+		switch (constant->type) {
+		case TYPE_BOOL:
+		case TYPE_INT:
+			b->Write (DH_PUSHNUMBER);
+			b->Write (atoi (constant->val));
+			break;
+		case TYPE_STRING:
+			b->WriteString (constant->val);
+			break;
+		case TYPE_VOID:
+		case TYPE_UNKNOWN:
+			break;
+		}
+	} else if ((g = FindGlobalVariable (token))) {
+		// Global variable
+		b->Write (DH_PUSHGLOBALVAR);
+		b->Write (g->index);
+	} else {
+		// If nothing else, check for literal
+		switch (reqtype) {
+		case TYPE_VOID:
+		case TYPE_UNKNOWN:
+			ParserError ("unknown identifier `%s` (expected keyword, function or variable)", token.chars());
+			break;
+		case TYPE_BOOL:
+		case TYPE_INT: {
+			MustNumber (true);
+			
+			// All values are written unsigned - thus we need to write the value's
+			// absolute value, followed by an unary minus for negatives.
+			b->Write (DH_PUSHNUMBER);
+			
+			long v = atol (token);
+			b->Write (static_cast<word> (abs (v)));
+			if (v < 0)
+				b->Write (DH_UNARYMINUS);
+			break;
+		}
+		case TYPE_STRING:
+			// PushToStringTable either returns the string index of the
+			// string if it finds it in the table, or writes it to the
+			// table and returns it index if it doesn't find it there.
+			MustString (true);
+			b->WriteString (token);
+			break;
+		}
+	}
+	
+	// Negate it now if desired
+	if (negate)
+		b->Write (DH_NEGATELOGICAL);
+	
+	return b;
+}
+
+// ============================================================================
+// Parses an assignment. An assignment starts with a variable name, followed
+// by an assignment operator, followed by an expression value. Expects current
+// token to be the name of the variable, and expects the variable to be given.
+DataBuffer* ScriptReader::ParseAssignment (ScriptVar* var) {
+	bool global = !var->statename.len ();
+	
+	// Get an operator
+	MustNext ();
+	int oper = ParseOperator ();
+	if (!IsAssignmentOperator (oper))
+		ParserError ("expected assignment operator");
+	
+	if (g_CurMode == MODE_TOPLEVEL) // TODO: lift this restriction
+		ParserError ("can't alter variables at top level");
+	
+	// Parse the right operand
+	MustNext ();
+	DataBuffer* retbuf = new DataBuffer;
+	DataBuffer* expr = ParseExpression (var->type);
+	
+	// <<= and >>= do not have data headers. Solution: expand them.
+	// a <<= b -> a = a << b
+	// a >>= b -> a = a >> b
+	if (oper == OPER_ASSIGNLEFTSHIFT || oper == OPER_ASSIGNRIGHTSHIFT) {
+		retbuf->Write (global ? DH_PUSHGLOBALVAR : DH_PUSHLOCALVAR);
+		retbuf->Write (var->index);
+		retbuf->Merge (expr);
+		retbuf->Write ((oper == OPER_ASSIGNLEFTSHIFT) ? DH_LSHIFT : DH_RSHIFT);
+		retbuf->Write (global ? DH_ASSIGNGLOBALVAR : DH_ASSIGNLOCALVAR);
+		retbuf->Write (var->index);
+	} else {
+		retbuf->Merge (expr);
+		long dh = DataHeaderByOperator (var, oper);
+		retbuf->Write (dh);
+		retbuf->Write (var->index);
+	}
+	
+	return retbuf;
+}
+
+void ScriptReader::PushScope () {
+	g_ScopeCursor++;
+	if (g_ScopeCursor >= MAX_SCOPE)
+		ParserError ("too deep scope");
+	
+	ScopeInfo* info = &SCOPE(0);
+	info->type = SCOPETYPE_UNKNOWN;
+	info->mark1 = 0;
+	info->mark2 = 0;
+	info->buffer1 = NULL;
+	info->casecursor = -1;
+	for (int i = 0; i < MAX_CASE; i++) {
+		info->casemarks[i] = MAX_MARKS;
+		info->casebuffers[i] = NULL;
+		info->casenumbers[i] = -1;
+	}
+}
+
+DataBuffer* ScriptReader::ParseStatement (ObjWriter* w) {
+	if (FindConstant (token)) // There should not be constants here.
+		ParserError ("invalid use for constant\n");
+	
+	// If it's a variable, expect assignment.
+	if (ScriptVar* var = FindGlobalVariable (token))
+		return ParseAssignment (var);
+	
+	return NULL;
+}
+
+void ScriptReader::AddSwitchCase (ObjWriter* w, DataBuffer* b) {
+	ScopeInfo* info = &SCOPE(0);
+	
+	info->casecursor++;
+	if (info->casecursor >= MAX_CASE)
+		ParserError ("too many cases in one switch");
+	
+	// Init a mark for the case buffer
+	int m = w->AddMark ("");
+	info->casemarks[info->casecursor] = m;
+	
+	// Add a reference to the mark. "case" and "default" both
+	// add the necessary bytecode before the reference.
+	if (b)
+		b->AddMarkReference (m);
+	else
+		w->AddReference (m);
+	
+	// Init a buffer for the case block and tell the object
+	// writer to record all written data to it.
+	info->casebuffers[info->casecursor] = w->SwitchBuffer = new DataBuffer;
+}
+
+constinfo_t* FindConstant (str token) {
+	for (uint i = 0; i < g_ConstInfo.size(); i++)
+		if (g_ConstInfo[i].name == token)
+			return &g_ConstInfo[i];
+	return NULL;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/preprocessor.cxx	Fri Jan 10 16:11:49 2014 +0200
@@ -0,0 +1,126 @@
+/*
+ *	botc source code
+ *	Copyright (C) 2012 Santeri `Dusk` Piippo
+ *	All rights reserved.
+ *	
+ *	Redistribution and use in source and binary forms, with or without
+ *	modification, are permitted provided that the following conditions are met:
+ *	
+ *	1. Redistributions of source code must retain the above copyright notice,
+ *	   this list of conditions and the following disclaimer.
+ *	2. Redistributions in binary form must reproduce the above copyright notice,
+ *	   this list of conditions and the following disclaimer in the documentation
+ *	   and/or other materials provided with the distribution.
+ *	3. Neither the name of the developer nor the names of its contributors may
+ *	   be used to endorse or promote products derived from this software without
+ *	   specific prior written permission.
+ *	4. Redistributions in any form must be accompanied by information on how to
+ *	   obtain complete source code for the software and any accompanying
+ *	   software that uses the software. The source code must either be included
+ *	   in the distribution or be available for no more than the cost of
+ *	   distribution plus a nominal fee, and must be freely redistributable
+ *	   under reasonable conditions. For an executable file, complete source
+ *	   code means the source code for all modules it contains. It does not
+ *	   include source code for modules or files that typically accompany the
+ *	   major components of the operating system on which the executable file
+ *	   runs.
+ *	
+ *	THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ *	AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ *	IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ *	ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ *	LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *	CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ *	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ *	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ *	POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define __PARSER_CXX__
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "common.h"
+#include "str.h"
+#include "scriptreader.h"
+
+/* Since the preprocessor is *called* from ReadChar and I don't want
+ * to worry about recursive preprocessing, the preprocessor uses its
+ * own bare-bones variant of the function for file reading.
+ */
+char ScriptReader::PPReadChar () {
+	char c;
+	if (!fread (&c, sizeof (char), 1, fp[fc]))
+		return 0;
+	curchar[fc]++;
+	return c;
+}
+
+void ScriptReader::PPMustChar (char c) {
+	char d = PPReadChar ();
+	if (c != d)
+		ParserError ("expected `%c`, got `%d`", c, d);
+}
+
+// ============================================================================
+// Reads a word until whitespace
+str ScriptReader::PPReadWord (char &term) {
+	str word;
+	while (1) {
+		char c = PPReadChar();
+		if (feof (fp[fc]) || (IsCharWhitespace (c) && word.len ())) {
+			term = c;
+			break;
+		}
+		word += c;
+	}
+	return word;
+}
+
+// ============================================================================
+// Preprocess any directives found in the script file
+void ScriptReader::PreprocessDirectives () {
+	size_t spos = ftell (fp[fc]);
+	if (!DoDirectivePreprocessing ())
+		fseek (fp[fc], spos, SEEK_SET);
+}
+
+/* ============================================================================
+ * Returns true if the pre-processing was successful, false if not.
+ * If pre-processing was successful, the file pointer remains where
+ * it was, if not, it's pushed back to where it was before preprocessing
+ * took place and is parsed normally.
+ */
+bool ScriptReader::DoDirectivePreprocessing () {
+	char trash;
+	// Directives start with a pound sign
+	if (PPReadChar() != '#')
+		return false;
+	
+	// Read characters until next whitespace to
+	// build the name of the directive
+	str directive = PPReadWord (trash);
+	
+	// Now check the directive name against known names
+	if (directive == "include") {
+		// #include-directive
+		char terminator;
+		str file = PPReadWord (terminator);
+		
+		if (!file.len())
+			ParserError ("expected file name for #include, got nothing instead");
+		OpenFile (file);
+		return true;
+	} else if (directive == "neurosphere") {
+		// #neurosphere - activates neurosphere compatibility, aka stuff
+		// that is still WIP and what main zandronum does not yet support.
+		// Most end users should never need this.
+		g_Neurosphere = true;
+		return true;
+	}
+	
+	ParserError ("unknown directive `#%s`!", directive.chars());
+	return false;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/scriptreader.cxx	Fri Jan 10 16:11:49 2014 +0200
@@ -0,0 +1,412 @@
+/*
+ *	botc source code
+ *	Copyright (C) 2012 Santeri `Dusk` Piippo
+ *	All rights reserved.
+ *	
+ *	Redistribution and use in source and binary forms, with or without
+ *	modification, are permitted provided that the following conditions are met:
+ *	
+ *	1. Redistributions of source code must retain the above copyright notice,
+ *	   this list of conditions and the following disclaimer.
+ *	2. Redistributions in binary form must reproduce the above copyright notice,
+ *	   this list of conditions and the following disclaimer in the documentation
+ *	   and/or other materials provided with the distribution.
+ *	3. Neither the name of the developer nor the names of its contributors may
+ *	   be used to endorse or promote products derived from this software without
+ *	   specific prior written permission.
+ *	4. Redistributions in any form must be accompanied by information on how to
+ *	   obtain complete source code for the software and any accompanying
+ *	   software that uses the software. The source code must either be included
+ *	   in the distribution or be available for no more than the cost of
+ *	   distribution plus a nominal fee, and must be freely redistributable
+ *	   under reasonable conditions. For an executable file, complete source
+ *	   code means the source code for all modules it contains. It does not
+ *	   include source code for modules or files that typically accompany the
+ *	   major components of the operating system on which the executable file
+ *	   runs.
+ *	
+ *	THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ *	AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ *	IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ *	ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ *	LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *	CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ *	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ *	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ *	POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "string.h"
+#include "str.h"
+#include "common.h"
+#include "scriptreader.h"
+
+#define STORE_POSITION \
+	bool _atnewline = atnewline; \
+	unsigned int _curline = curline[fc]; \
+	unsigned int _curchar = curchar[fc];
+
+#define RESTORE_POSITION \
+	atnewline = _atnewline; \
+	curline[fc] = _curline; \
+	curchar[fc] = _curchar;
+
+// ============================================================================
+ScriptReader::ScriptReader (str path) {
+	token = "";
+	prevtoken = "";
+	prevpos = 0;
+	fc = -1;
+	
+	for (unsigned int u = 0; u < MAX_FILESTACK; u++)
+		fp[u] = NULL;
+	
+	OpenFile (path);
+	commentmode = 0;
+}
+
+// ============================================================================
+ScriptReader::~ScriptReader () {
+	// If comment mode is 2 by the time the file ended, the
+	// comment was left unterminated. 1 is no problem, since
+	// it's terminated by newlines anyway.
+	if (commentmode == 2)
+		ParserError ("unterminated `/*`-style comment");
+	
+	for (unsigned int u = 0; u < MAX_FILESTACK; u++) {
+		if (fp[u]) {
+			ParserWarning ("file idx %u remained open after parsing", u);
+			CloseFile (u);
+		}
+	}
+}
+
+// ============================================================================
+// Opens a file and pushes its pointer to stack
+void ScriptReader::OpenFile (str path) {
+	if (fc+1 >= MAX_FILESTACK) 
+		ParserError ("supposed to open file `%s` but file stack is full! do you have recursive `#include` directives?",
+			path.chars());
+	
+	// Save the position first.
+	if (fc != -1) {
+		savedpos[fc] = ftell (fp[fc]);
+	}
+	
+	fc++;
+	
+	fp[fc] = fopen (path, "r");
+	if (!fp[fc]) {
+		ParserError ("couldn't open %s for reading!\n", path.chars ());
+		exit (1);
+	}
+	
+	fseek (fp[fc], 0, SEEK_SET);
+	filepath[fc] = path.chars();
+	curline[fc] = 1;
+	curchar[fc] = 1;
+	pos[fc] = 0;
+	atnewline = 0;
+}
+
+// ============================================================================
+// Closes the current file
+void ScriptReader::CloseFile (unsigned int u) {
+	if (u >= MAX_FILESTACK)
+		u = fc;
+	
+	if (!fp[u])
+		return;
+	
+	fclose (fp[u]);
+	fp[u] = NULL;
+	fc--;
+	
+	if (fc != -1)
+		fseek (fp[fc], savedpos[fc], SEEK_SET);
+}
+
+// ============================================================================
+char ScriptReader::ReadChar () {
+	if (feof (fp[fc]))
+		return 0;
+	
+	char c;
+	if (!fread (&c, 1, 1, fp[fc]))
+		return 0;
+	
+	// We're at a newline, thus next char read will begin the next line
+	if (atnewline) {
+		atnewline = false;
+		curline[fc]++;
+		curchar[fc] = 0; // gets incremented to 1
+	}
+	
+	if (c == '\n') {
+		atnewline = true;
+		
+		// Check for pre-processor directives
+		PreprocessDirectives ();
+	}
+	
+	curchar[fc]++;
+	return c;
+}
+
+// ============================================================================
+// Peeks the next character
+char ScriptReader::PeekChar (int offset) {
+	// Store current position
+	long curpos = ftell (fp[fc]);
+	STORE_POSITION
+	
+	// Forward by offset
+	fseek (fp[fc], offset, SEEK_CUR);
+	
+	// Read the character
+	char* c = (char*)malloc (sizeof (char));
+	
+	if (!fread (c, sizeof (char), 1, fp[fc])) {
+		fseek (fp[fc], curpos, SEEK_SET);
+		return 0;
+	}
+	
+	// Rewind back
+	fseek (fp[fc], curpos, SEEK_SET);
+	RESTORE_POSITION
+	
+	return c[0];
+}
+
+// ============================================================================
+// Read a token from the file buffer. Returns true if token was found, false if not.
+bool ScriptReader::Next (bool peek) {
+	prevpos = ftell (fp[fc]);
+	str tmp = "";
+	
+	while (1) {
+		// Check end-of-file
+		if (feof (fp[fc])) {
+			// If we're just peeking, we shouldn't
+			// actually close anything.. 
+			if (peek)
+				break;
+			
+			CloseFile ();
+			if (fc == -1)
+				break;
+		}
+		
+		// Check if the next token possibly starts a comment.
+		if (PeekChar () == '/' && !tmp.len()) {
+			char c2 = PeekChar (1);
+			// C++-style comment
+			if (c2 == '/')
+				commentmode = 1;
+			else if (c2 == '*')
+				commentmode = 2;
+			
+			// We don't need to actually read in the
+			// comment characters, since they will get
+			// ignored due to comment mode anyway.
+		}
+		
+		c = ReadChar ();
+		
+		// If this is a comment we're reading, check if this character
+		// gets the comment terminated, otherwise ignore it.
+		if (commentmode > 0) {
+			if (commentmode == 1 && c == '\n') {
+				// C++-style comments are terminated by a newline
+				commentmode = 0;
+				continue;
+			} else if (commentmode == 2 && c == '*') {
+				// C-style comments are terminated by a `*/`
+				if (PeekChar() == '/') {
+					commentmode = 0;
+					ReadChar ();
+				}
+			}
+			
+			// Otherwise, ignore it.
+			continue;
+		}
+		
+		// Non-alphanumber characters (sans underscore) break the word too.
+		// If there was prior data, the delimeter pushes the cursor back so
+		// that the next character will be the same delimeter. If there isn't,
+		// the delimeter itself is included (and thus becomes a token itself.)
+		if ((c >= 33 && c <= 47) ||
+			(c >= 58 && c <= 64) ||
+			(c >= 91 && c <= 96 && c != '_') ||
+			(c >= 123 && c <= 126)) {
+			if (tmp.len())
+				fseek (fp[fc], ftell (fp[fc]) - 1, SEEK_SET);
+			else
+				tmp += c;
+			break;
+		}
+		
+		if (IsCharWhitespace (c)) {
+			// Don't break if we haven't gathered anything yet.
+			if (tmp.len())
+				break;
+		} else {
+			tmp += c;
+		}
+	}
+	
+	// If we got nothing here, read failed. This should
+	// only happen in the case of EOF.
+	if (!tmp.len()) {
+		token = "";
+		return false;
+	}
+	
+	pos[fc]++;
+	prevtoken = token;
+	token = tmp;
+	return true;
+}
+
+// ============================================================================
+// Returns the next token without advancing the cursor.
+str ScriptReader::PeekNext (int offset) {
+	// Store current information
+	str storedtoken = token;
+	int cpos = ftell (fp[fc]);
+	STORE_POSITION
+	
+	// Advance on the token.
+	while (offset >= 0) {
+		if (!Next (true))
+			return "";
+		offset--;
+	}
+	
+	str tmp = token;
+	
+	// Restore position
+	fseek (fp[fc], cpos, SEEK_SET);
+	pos[fc]--;
+	token = storedtoken;
+	RESTORE_POSITION
+	return tmp;
+}
+
+// ============================================================================
+void ScriptReader::Seek (unsigned int n, int origin) {
+	switch (origin) {
+	case SEEK_SET:
+		fseek (fp[fc], 0, SEEK_SET);
+		pos[fc] = 0;
+		break;
+	case SEEK_CUR:
+		break;
+	case SEEK_END:
+		printf ("ScriptReader::Seek: SEEK_END not yet supported.\n");
+		break;
+	}
+	
+	for (unsigned int i = 0; i < n+1; i++)
+		Next();
+}
+
+// ============================================================================
+void ScriptReader::MustNext (const char* c) {
+	if (!Next()) {
+		if (strlen (c))
+			ParserError ("expected `%s`, reached end of file instead\n", c);
+		else
+			ParserError ("expected a token, reached end of file instead\n");
+	}
+	
+	if (strlen (c))
+		MustThis (c);
+}
+
+// ============================================================================
+void ScriptReader::MustThis (const char* c) {
+	if (token != c)
+		ParserError ("expected `%s`, got `%s` instead", c, token.chars());
+}
+
+// ============================================================================
+void ScriptReader::ParserError (const char* message, ...) {
+	PERFORM_FORMAT (message, outmessage);
+	ParserMessage ("\nError: ", outmessage);
+	exit (1);
+}
+
+// ============================================================================
+void ScriptReader::ParserWarning (const char* message, ...) {
+	PERFORM_FORMAT (message, outmessage);
+	ParserMessage ("Warning: ", outmessage);
+}
+
+// ============================================================================
+void ScriptReader::ParserMessage (const char* header, char* message) {
+	if (fc >= 0 && fc < MAX_FILESTACK)
+		fprintf (stderr, "%s%s:%u:%u: %s\n",
+			header, filepath[fc], curline[fc], curchar[fc], message);
+	else
+		fprintf (stderr, "%s%s\n", header, message);
+}
+
+// ============================================================================
+// if gotquote == 1, the current token already holds the quotation mark.
+void ScriptReader::MustString (bool gotquote) {
+	if (gotquote)
+		MustThis ("\"");
+	else
+		MustNext ("\"");
+	
+	str string;
+	// Keep reading characters until we find a terminating quote.
+	while (1) {
+		// can't end here!
+		if (feof (fp[fc]))
+			ParserError ("unterminated string");
+		
+		char c = ReadChar ();
+		if (c == '"')
+			break;
+		
+		string += c;
+	}
+	
+	token = string;
+}
+
+// ============================================================================
+void ScriptReader::MustNumber (bool fromthis) {
+	if (!fromthis)
+		MustNext ();
+	
+	str num = token;
+	if (num == "-") {
+		MustNext ();
+		num += token;
+	}
+	
+	// "true" and "false" are valid numbers
+	if (!token.icompare ("true"))
+		token = "1";
+	else if (!token.icompare ("false"))
+		token = "0";
+	else {
+		if (!token.isnumber())
+			ParserError ("expected a number, got `%s`", num.chars());
+		
+		str check;
+		check.appendformat ("%d", atoi (num));
+		if (token != check)
+			ParserWarning ("integer too large: %s -> %s", num.chars(), check.chars());
+		
+		token = num;
+	}
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/scriptreader.h	Fri Jan 10 16:11:49 2014 +0200
@@ -0,0 +1,211 @@
+/*
+ *	botc source code
+ *	Copyright (C) 2012 Santeri `Dusk` Piippo
+ *	All rights reserved.
+ *	
+ *	Redistribution and use in source and binary forms, with or without
+ *	modification, are permitted provided that the following conditions are met:
+ *	
+ *	1. Redistributions of source code must retain the above copyright notice,
+ *	   this list of conditions and the following disclaimer.
+ *	2. Redistributions in binary form must reproduce the above copyright notice,
+ *	   this list of conditions and the following disclaimer in the documentation
+ *	   and/or other materials provided with the distribution.
+ *	3. Neither the name of the developer nor the names of its contributors may
+ *	   be used to endorse or promote products derived from this software without
+ *	   specific prior written permission.
+ *	4. Redistributions in any form must be accompanied by information on how to
+ *	   obtain complete source code for the software and any accompanying
+ *	   software that uses the software. The source code must either be included
+ *	   in the distribution or be available for no more than the cost of
+ *	   distribution plus a nominal fee, and must be freely redistributable
+ *	   under reasonable conditions. For an executable file, complete source
+ *	   code means the source code for all modules it contains. It does not
+ *	   include source code for modules or files that typically accompany the
+ *	   major components of the operating system on which the executable file
+ *	   runs.
+ *	
+ *	THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ *	AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ *	IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ *	ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ *	LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *	CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ *	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ *	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ *	POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __SCRIPTREADER_H__
+#define __SCRIPTREADER_H__
+
+#include <stdio.h>
+#include "str.h"
+#include "commands.h"
+#include "objwriter.h"
+
+#define MAX_FILESTACK 8
+#define MAX_SCOPE 32
+#define MAX_CASE 64
+
+class ScriptVar;
+
+// Operators
+enum operator_e {
+	OPER_ADD,
+	OPER_SUBTRACT,
+	OPER_MULTIPLY,
+	OPER_DIVIDE,
+	OPER_MODULUS,
+	OPER_ASSIGN,
+	OPER_ASSIGNADD,
+	OPER_ASSIGNSUB,
+	OPER_ASSIGNMUL,
+	OPER_ASSIGNDIV,
+	OPER_ASSIGNMOD, // -- 10
+	OPER_EQUALS,
+	OPER_NOTEQUALS,
+	OPER_LESSTHAN,
+	OPER_GREATERTHAN,
+	OPER_LESSTHANEQUALS,
+	OPER_GREATERTHANEQUALS,
+	OPER_LEFTSHIFT,
+	OPER_RIGHTSHIFT,
+	OPER_ASSIGNLEFTSHIFT,
+	OPER_ASSIGNRIGHTSHIFT, // -- 20
+	OPER_OR,
+	OPER_AND,
+	OPER_BITWISEOR,
+	OPER_BITWISEAND,
+	OPER_BITWISEEOR,
+	OPER_TERNARY,
+	OPER_STRLEN,
+};
+
+// Mark types
+enum marktype_e {
+	MARKTYPE_LABEL,
+	MARKTYPE_IF,
+	MARKTYPE_INTERNAL, // internal structures
+};
+
+// Block types
+enum scopetype_e {
+	SCOPETYPE_UNKNOWN,
+	SCOPETYPE_IF,
+	SCOPETYPE_WHILE,
+	SCOPETYPE_FOR,
+	SCOPETYPE_DO,
+	SCOPETYPE_SWITCH,
+	SCOPETYPE_ELSE,
+};
+
+// ============================================================================
+// Meta-data about blocks
+struct ScopeInfo {
+	unsigned int mark1;
+	unsigned int mark2;
+	scopetype_e type;
+	DataBuffer* buffer1;
+	
+	// switch-related stuff
+	// Which case are we at?
+	short casecursor;
+	
+	// Marks to case-blocks
+	int casemarks[MAX_CASE];
+	
+	// Numbers of the case labels
+	int casenumbers[MAX_CASE];
+	
+	// actual case blocks
+	DataBuffer* casebuffers[MAX_CASE];
+	
+	// What is the current buffer of the block?
+	DataBuffer* recordbuffer;
+};
+
+// ============================================================================
+typedef struct {
+	str name;
+	type_e type;
+	str val;
+} constinfo_t;
+
+// ============================================================================
+// The script reader reads the script, parses it and tells the object writer
+// the bytecode it needs to write to file.
+class ScriptReader {
+public:
+	// ====================================================================
+	// MEMBERS
+	FILE* fp[MAX_FILESTACK];
+	char* filepath[MAX_FILESTACK];
+	int fc;
+	
+	unsigned int pos[MAX_FILESTACK];
+	unsigned int curline[MAX_FILESTACK];
+	unsigned int curchar[MAX_FILESTACK];
+	ScopeInfo scopestack[MAX_SCOPE];
+	long savedpos[MAX_FILESTACK]; // filepointer cursor position
+	str token;
+	int commentmode;
+	long prevpos;
+	str prevtoken;
+	
+	// ====================================================================
+	// METHODS
+	// scriptreader.cxx:
+	ScriptReader (str path);
+	~ScriptReader ();
+	void OpenFile (str path);
+	void CloseFile (unsigned int u = MAX_FILESTACK);
+	char ReadChar ();
+	char PeekChar (int offset = 0);
+	bool Next (bool peek = false);
+	void Prev ();
+	str PeekNext (int offset = 0);
+	void Seek (unsigned int n, int origin);
+	void MustNext (const char* c = "");
+	void MustThis (const char* c);
+	void MustString (bool gotquote = false);
+	void MustNumber (bool fromthis = false);
+	void MustBool ();
+	bool BoolValue ();
+	
+	void ParserError (const char* message, ...);
+	void ParserWarning (const char* message, ...);
+	
+	// parser.cxx:
+	void ParseBotScript (ObjWriter* w);
+	DataBuffer* ParseCommand (CommandDef* comm);
+	DataBuffer* ParseExpression (type_e reqtype);
+	DataBuffer* ParseAssignment (ScriptVar* var);
+	int ParseOperator (bool peek = false);
+	DataBuffer* ParseExprValue (type_e reqtype);
+	str ParseFloat ();
+	void PushScope ();
+	
+	// preprocessor.cxx:
+	void PreprocessDirectives ();
+	void PreprocessMacros ();
+	DataBuffer* ParseStatement (ObjWriter* w);
+	void AddSwitchCase (ObjWriter* w, DataBuffer* b);
+	
+private:
+	bool atnewline;
+	char c;
+	void ParserMessage (const char* header, char* message);
+	
+	bool DoDirectivePreprocessing ();
+	char PPReadChar ();
+	void PPMustChar (char c);
+	str PPReadWord (char &term);
+};
+
+constinfo_t* FindConstant (str token);
+extern bool g_Neurosphere;
+
+#endif // __SCRIPTREADER_H__
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/str.cxx	Fri Jan 10 16:11:49 2014 +0200
@@ -0,0 +1,426 @@
+/*
+ *	botc source code
+ *	Copyright (C) 2012 Santeri `Dusk` Piippo
+ *	All rights reserved.
+ *	
+ *	Redistribution and use in source and binary forms, with or without
+ *	modification, are permitted provided that the following conditions are met:
+ *	
+ *	1. Redistributions of source code must retain the above copyright notice,
+ *	   this list of conditions and the following disclaimer.
+ *	2. Redistributions in binary form must reproduce the above copyright notice,
+ *	   this list of conditions and the following disclaimer in the documentation
+ *	   and/or other materials provided with the distribution.
+ *	3. Neither the name of the developer nor the names of its contributors may
+ *	   be used to endorse or promote products derived from this software without
+ *	   specific prior written permission.
+ *	4. Redistributions in any form must be accompanied by information on how to
+ *	   obtain complete source code for the software and any accompanying
+ *	   software that uses the software. The source code must either be included
+ *	   in the distribution or be available for no more than the cost of
+ *	   distribution plus a nominal fee, and must be freely redistributable
+ *	   under reasonable conditions. For an executable file, complete source
+ *	   code means the source code for all modules it contains. It does not
+ *	   include source code for modules or files that typically accompany the
+ *	   major components of the operating system on which the executable file
+ *	   runs.
+ *	
+ *	THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ *	AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ *	IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ *	ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ *	LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *	CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ *	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ *	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ *	POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include "array.h"
+#include "str.h"
+#include "common.h"
+
+#define ITERATE_STRING(u) \
+	for (unsigned int u = 0; u < strlen (text); u++)
+
+// ============================================================================
+// vdynformat: Try to write to a formatted string with size bytes first, if
+// that fails, double the size and keep recursing until it works.
+char* vdynformat (const char* c, va_list v, unsigned int size) {
+	char* buffer = new char[size];
+	int r = vsnprintf (buffer, size-1, c, v);
+	if (r > (int)size-1 || r < 0) {
+		delete buffer;
+		buffer = vdynformat (c, v, size*2);
+	}
+	return buffer;
+}
+
+// ============================================================================
+str::str () {
+	text = new char[1];
+	clear();
+	alloclen = strlen (text);
+}
+
+str::str (const char* c) {
+	text = new char[1];
+	clear ();
+	alloclen = strlen (text);
+	append (c);
+}
+
+str::str (char c) {
+	text = new char[1];
+	clear ();
+	alloclen = strlen (text);
+	append (c);
+}
+
+// ============================================================================
+void str::clear () {
+	delete text;
+	text = new char[1];
+	text[0] = '\0';
+	curs = 0;
+}
+
+unsigned int str::len () {return strlen(text);}
+
+// ============================================================================
+void str::resize (unsigned int len) {
+	unsigned int oldlen = strlen (text);
+	char* oldtext = new char[oldlen];
+	strncpy (oldtext, text, oldlen);
+	
+	delete text;
+	text = new char[len+1];
+	for (unsigned int u = 0; u < len+1; u++)
+		text[u] = 0;
+	strncpy (text, oldtext, len);
+	
+	alloclen = len;
+}
+
+// ============================================================================
+void str::dump () {
+	for (unsigned int u = 0; u <= alloclen; u++)
+		printf ("\t%u. %u (%c)\n", u, text[u], text[u]);
+}
+
+// ============================================================================
+// Adds a new character at the end of the string.
+void str::append (char c) {
+	// Out of space, thus resize
+	if (curs == alloclen)
+		resize (alloclen+1);
+	text[curs] = c;
+	curs++;
+}
+
+void str::append (const char* c) {
+	resize (alloclen + strlen (c));
+	
+	for (unsigned int u = 0; u < strlen (c); u++) {
+		if (c[u] != 0)
+			append (c[u]);
+	}
+}
+
+void str::append (str c) {
+	append (c.chars());
+}
+
+// ============================================================================
+void str::appendformat (const char* c, ...) {
+	va_list v;
+	
+	va_start (v, c);
+	char* buf = vdynformat (c, v, 256);
+	va_end (v);
+	
+	append (buf);
+}
+
+void str::appendformat (str c, ...) {
+	va_list v;
+	
+	va_start (v, c);
+	char* buf = vdynformat (c.chars(), v, 256);
+	va_end (v);
+	
+	append (buf);
+}
+
+// ============================================================================
+char* str::chars () {
+	return text;
+}
+
+// ============================================================================
+unsigned int str::first (const char* c, unsigned int a) {
+	unsigned int r = 0;
+	unsigned int index = 0;
+	for (; a < alloclen; a++) {
+		if (text[a] == c[r]) {
+			if (r == 0)
+				index = a;
+			
+			r++;
+			if (r == strlen (c))
+				return index;
+		} else {
+			if (r != 0) {
+				// If the string sequence broke at this point, we need to
+				// check this character again, for a new sequence just
+				// might start right here.
+				a--;
+			}
+			
+			r = 0;
+		}
+	}
+	
+	return len ();
+}
+
+// ============================================================================
+unsigned int str::last (const char* c, int a) {
+	if (a == -1)
+		a = len();
+	
+	int max = strlen (c)-1;
+	
+	int r = max;
+	for (; a >= 0; a--) {
+		if (text[a] == c[r]) {
+			r--;
+			if (r == -1)
+				return a;
+		} else {
+			if (r != max)
+				a++;
+			
+			r = max;
+		}
+	}
+	
+	return len ();
+}
+
+// ============================================================================
+str str::substr (unsigned int a, unsigned int b) {
+	if (a > len()) a = len();
+	if (b > len()) b = len();
+	
+	if (b == a)
+		return "";
+	
+	if (b < a) {
+		printf ("str::substr: indices %u and %u given, should be the other way around, swapping..\n", a, b);
+		
+		// Swap the variables
+		unsigned int c = a;
+		a = b;
+		b = c;
+	}
+	
+	char* s = new char[b-a];
+	strncpy (s, text+a, b-a);
+	return str(s);
+}
+
+// ============================================================================
+void str::remove (unsigned int idx, unsigned int dellen) {
+	str s1 = substr (0, idx);
+	str s2 = substr (idx + dellen, len());
+	
+	clear();
+	
+	append (s1);
+	append (s2);
+}
+
+// ============================================================================
+void str::trim (int dellen) {
+	if (!dellen)
+		return;
+	
+	unsigned int delpos;
+	if (dellen > 0) {
+		delpos = len()-dellen;
+		text[delpos] = 0;
+		curs -= dellen;
+	} else {
+		str s = substr (-dellen, len());
+		clear();
+		append (s);
+	}
+}
+
+// ============================================================================
+void str::replace (const char* o, const char* n, unsigned int a) {
+	unsigned int idx;
+	
+	while ((idx = first (o, a)) != len()) {
+		str s1 = substr (0, idx);
+		str s2 = substr (idx + strlen (o), len());
+		
+		clear();
+		
+		append (s1);
+		append (n);
+		append (s2);
+	}
+}
+
+void str::insert (char* c, unsigned int pos) {
+	str s1 = substr (0, pos);
+	str s2 = substr (pos, len());
+	
+	clear();
+	append (s1);
+	append (c);
+	append (s2);
+}
+
+void str::reverse () {
+	char* tmp = new char[alloclen];
+	strcpy (tmp, text);
+	
+	clear();
+	curs = 0;
+	resize (alloclen);
+	for (int i = alloclen-1; i >= 0; i--)
+		append (tmp[i]);
+}
+
+void str::repeat (unsigned int n) {
+	char* tmp = new char[alloclen];
+	strcpy (tmp, text);
+	
+	for (; n > 0; n--)
+		append (tmp);
+}
+
+// ============================================================================
+bool str::isnumber () {
+	ITERATE_STRING (u) {
+		// Minus sign as the first character is allowed for negatives
+		if (!u && text[u] == '-')
+			continue;
+		
+		if (text[u] < '0' || text[u] > '9')
+			return false;
+	}
+	return true;
+}
+
+// ============================================================================
+bool str::isword () {
+	ITERATE_STRING (u) {
+		// lowercase letters
+		if (text[u] >= 'a' || text[u] <= 'z')
+			continue;
+		
+		// uppercase letters
+		if (text[u] >= 'A' || text[u] <= 'Z')
+			continue;
+		
+		return false;
+	}
+	return true;
+}
+
+// ============================================================================
+int str::compare (const char* c) {
+	return strcmp (text, c);
+}
+
+int str::compare (str c) {
+	return compare (c.chars());
+}
+
+int str::icompare (const char* c) {
+	return icompare (str ((char*)c));
+}
+
+int str::icompare (str b) {
+	return strcmp (tolower().chars(), b.tolower().chars());
+}
+
+// ============================================================================
+str str::tolower () {
+	str n = text;
+	
+	for (uint u = 0; u < len(); u++) {
+		if (n[u] > 'A' && n[u] < 'Z')
+			n.text[u] += ('a' - 'A');
+	}
+	
+	return n;
+}
+
+// ============================================================================
+str str::toupper () {
+	str n = text;
+	
+	for (uint u = 0; u < len(); u++) {
+		if (n[u] > 'a' && n[u] < 'z')
+			n.text[u] -= ('A' - 'a');
+	}
+	
+	return n;
+}
+
+// ============================================================================
+unsigned int str::count (char* c) {
+	unsigned int r = 0;
+	unsigned int tmp = 0;
+	ITERATE_STRING (u) {
+		if (text[u] == c[r]) {
+			r++;
+			if (r == strlen (c)) {
+				r = 0;
+				tmp++;
+			}
+		} else {
+			if (r != 0)
+				u--;
+			r = 0;
+		}
+	}
+	
+	return tmp;
+}
+
+// ============================================================================
+array<str> str::split (str del) {
+	array<str> res;
+	unsigned int a = 0;
+	
+	// Find all separators and store the text left to them.
+	while (1) {
+		unsigned int b = first (del, a);
+		
+		if (b == len())
+			break;
+		
+		res.push (substr (a, b));
+		a = b + strlen (del);
+	}
+	
+	// Add the string at the right of the last separator
+	res.push (substr (a, len()));
+	return res;
+}
+
+array<str> str::operator/ (str splitstring) {return split(splitstring);}
+array<str> str::operator/ (char* splitstring) {return split(splitstring);}
+array<str> str::operator/ (const char* splitstring) {return split(splitstring);}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/str.h	Fri Jan 10 16:11:49 2014 +0200
@@ -0,0 +1,233 @@
+/*
+ *	botc source code
+ *	Copyright (C) 2012 Santeri `Dusk` Piippo
+ *	All rights reserved.
+ *	
+ *	Redistribution and use in source and binary forms, with or without
+ *	modification, are permitted provided that the following conditions are met:
+ *	
+ *	1. Redistributions of source code must retain the above copyright notice,
+ *	   this list of conditions and the following disclaimer.
+ *	2. Redistributions in binary form must reproduce the above copyright notice,
+ *	   this list of conditions and the following disclaimer in the documentation
+ *	   and/or other materials provided with the distribution.
+ *	3. Neither the name of the developer nor the names of its contributors may
+ *	   be used to endorse or promote products derived from this software without
+ *	   specific prior written permission.
+ *	4. Redistributions in any form must be accompanied by information on how to
+ *	   obtain complete source code for the software and any accompanying
+ *	   software that uses the software. The source code must either be included
+ *	   in the distribution or be available for no more than the cost of
+ *	   distribution plus a nominal fee, and must be freely redistributable
+ *	   under reasonable conditions. For an executable file, complete source
+ *	   code means the source code for all modules it contains. It does not
+ *	   include source code for modules or files that typically accompany the
+ *	   major components of the operating system on which the executable file
+ *	   runs.
+ *	
+ *	THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ *	AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ *	IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ *	ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ *	LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *	CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ *	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ *	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ *	POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __STR_H__
+#define __STR_H__
+
+template<class T> class array;
+
+char* vdynformat (const char* c, va_list v, unsigned int size);
+
+#define SCCF_NUMBER	1<<0
+#define SCCF_WORD	1<<1
+
+// Dynamic string object, allocates memory when needed and
+// features a good bunch of manipulation methods
+class str {
+private:
+	// The actual message
+	char* text;
+	
+	// Where will append() place new characters?
+	unsigned int curs;
+	
+	// Allocated length
+	unsigned int alloclen;
+	
+	// Resize the text buffer to len characters
+	void resize (unsigned int len);
+public:
+	// ======================================================================
+	// CONSTRUCTORS
+	str ();
+	str (const char* c);
+	str (char c);
+	
+	// ======================================================================
+	// METHODS
+	
+	// Empty the string
+	void clear ();
+	
+	// Length of the string
+	unsigned int len ();
+	
+	// The char* form of the string
+	char* chars ();
+	
+	// Dumps the character table of the string
+	void dump ();
+	
+	// Appends text to the string
+	void append (char c);
+	void append (const char* c);
+	void append (str c);
+	
+	// Appends formatted text to the string.
+	void appendformat (const char* c, ...);
+	void appendformat (str c, ...);
+	
+	// Returns the first occurrence of c in the string, optionally starting
+	// from a certain position rather than the start.
+	unsigned int first (const char* c, unsigned int a = 0);
+	
+	// Returns the last occurrence of c in the string, optionally starting
+	// from a certain position rather than the end.
+	unsigned int last (const char* c, int a = -1);
+	
+	// Returns a substring of the string, from a to b.
+	str substr (unsigned int a, unsigned int b);
+	
+	// Replace a substring with another substring.
+	void replace (const char* o, const char* n, unsigned int a = 0);
+	
+	// Removes a given index from the string, optionally more characters than just 1.
+	void remove (unsigned int idx, unsigned int dellen=1);
+	
+	void trim (int dellen);
+	
+	// Inserts a substring into a certain position.
+	void insert (char* c, unsigned int pos);
+	
+	// Reverses the string.
+	void reverse ();
+	
+	// Repeats the string a given amount of times.
+	void repeat (unsigned int n);
+	
+	// Is the string a number?
+	bool isnumber ();
+	
+	// Is the string a word, i.e consists only of alphabetic letters?
+	bool isword ();
+	
+	// Convert string to lower case
+	str tolower ();
+	
+	// Convert string to upper case
+	str toupper ();
+	
+	// Compare this string with another
+	int compare (const char* c);
+	int compare (str c);
+	int icompare (str c);
+	int icompare (const char* c);
+	
+	// Counts the amount of substrings in the string
+	unsigned int count (char* s);
+	
+	array<str> split (str del);
+	
+	// ======================================================================
+	// OPERATORS
+	str operator+ (str& c) {
+		append (c);
+		return *this;
+	}
+	
+	str& operator+= (char c) {
+		append (c);
+		return *this;
+	}
+	
+	str& operator+= (const char* c) {
+		append (c);
+		return *this;
+	}
+	
+	str& operator+= (const str c) {
+		append (c);
+		return *this;
+	}
+	
+	str operator* (const int repcount) {
+		repeat (repcount);
+		return *this;
+	}
+	
+	str& operator*= (const int repcount) {
+		repeat (repcount);
+		return *this;
+	}
+	
+	str operator- (const int trimcount) {
+		trim (trimcount);
+		return *this;
+	}
+	
+	str& operator-= (const int trimcount) {
+		trim (trimcount);
+		return *this;
+	}
+	
+	array<str> operator/ (str splitstring);
+	array<str> operator/ (char* splitstring);
+	array<str> operator/ (const char* splitstring);
+	
+	str operator+ () {
+		return toupper ();
+	}
+	
+	str operator- () {
+		return tolower ();
+	}
+	
+	str operator! () {
+		reverse ();
+		return *this;
+	}
+	
+#define DEFINE_OPERATOR_TYPE(OPER, TYPE) \
+	bool operator OPER (TYPE other) {return compare(other) OPER 0;}
+#define DEFINE_OPERATOR(OPER) \
+	DEFINE_OPERATOR_TYPE (OPER, str) \
+	DEFINE_OPERATOR_TYPE (OPER, char*) \
+	DEFINE_OPERATOR_TYPE (OPER, const char*)
+	
+	DEFINE_OPERATOR (==)
+	DEFINE_OPERATOR (!=)
+	DEFINE_OPERATOR (>)
+	DEFINE_OPERATOR (<)
+	DEFINE_OPERATOR (>=)
+	DEFINE_OPERATOR (<=)
+	
+	char operator [] (unsigned int pos) {
+		return text[pos];
+	}
+	
+	operator char* () const {
+		return text;
+	}
+	
+	operator int () const {return atoi(text);}
+	operator unsigned int () const {return atoi(text);}
+};
+
+#endif // __STR_H__
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/stringtable.cxx	Fri Jan 10 16:11:49 2014 +0200
@@ -0,0 +1,104 @@
+/*
+ *	botc source code
+ *	Copyright (C) 2012 Santeri `Dusk` Piippo
+ *	All rights reserved.
+ *	
+ *	Redistribution and use in source and binary forms, with or without
+ *	modification, are permitted provided that the following conditions are met:
+ *	
+ *	1. Redistributions of source code must retain the above copyright notice,
+ *	   this list of conditions and the following disclaimer.
+ *	2. Redistributions in binary form must reproduce the above copyright notice,
+ *	   this list of conditions and the following disclaimer in the documentation
+ *	   and/or other materials provided with the distribution.
+ *	3. Neither the name of the developer nor the names of its contributors may
+ *	   be used to endorse or promote products derived from this software without
+ *	   specific prior written permission.
+ *	4. Redistributions in any form must be accompanied by information on how to
+ *	   obtain complete source code for the software and any accompanying
+ *	   software that uses the software. The source code must either be included
+ *	   in the distribution or be available for no more than the cost of
+ *	   distribution plus a nominal fee, and must be freely redistributable
+ *	   under reasonable conditions. For an executable file, complete source
+ *	   code means the source code for all modules it contains. It does not
+ *	   include source code for modules or files that typically accompany the
+ *	   major components of the operating system on which the executable file
+ *	   runs.
+ *	
+ *	THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ *	AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ *	IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ *	ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ *	LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *	CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ *	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ *	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ *	POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define __STRINGTABLE_CXX__
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "common.h"
+#include "bots.h"
+#include "stringtable.h"
+
+// ============================================================================
+// Initializes the string table
+void InitStringTable() {
+	// Zero out everything first.
+	for (unsigned int a = 0; a < MAX_LIST_STRINGS; a++)
+		for (unsigned int b = 0; b < MAX_STRING_LENGTH; b++)
+			g_StringTable[a][b] = 0;
+}
+
+// ============================================================================
+// Potentially adds a string to the table and returns the index of it.
+unsigned int PushToStringTable (char* s) {
+	// Must not be too long.
+	if (strlen (s) >= MAX_STRING_LENGTH)
+		error ("string `%s` too long (%d characters max)\n", s, strlen (s));
+	
+	// Find a free slot in the table. 
+	unsigned int a;
+	for (a = 0; a < MAX_LIST_STRINGS; a++) {
+		// String is already in the table, thus return it.
+		if (!strcmp (s, g_StringTable[a]))
+			return a;
+		
+		// String is empty, thus it's free.
+		if (!strlen (g_StringTable[a]))
+			break;
+	}
+	
+	// no free slots!
+	if (a == MAX_LIST_STRINGS)
+		error ("too many strings defined!\n");
+	
+	// Determine the length
+	size_t l1 = strlen (s);
+	size_t l2 = MAX_LIST_STRINGS - 1;
+	size_t len = (l1 < l2) ? l1 : l2;
+	
+	// Now, dump the string into the slot
+	strncpy (g_StringTable[a], s, len);
+	g_StringTable[a][len] = 0;
+	
+	return a;
+}
+
+// ============================================================================
+// Counts the amount of strings in the table.
+unsigned int CountStringTable () {
+	unsigned int count = 0;
+	for (unsigned int a = 0; a < MAX_LIST_STRINGS; a++) {
+		if (!strlen (g_StringTable[a]))
+			break;
+		else
+			count++;
+	}
+	return count;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/stringtable.h	Fri Jan 10 16:11:49 2014 +0200
@@ -0,0 +1,50 @@
+/*
+ *	botc source code
+ *	Copyright (C) 2012 Santeri `Dusk` Piippo
+ *	All rights reserved.
+ *	
+ *	Redistribution and use in source and binary forms, with or without
+ *	modification, are permitted provided that the following conditions are met:
+ *	
+ *	1. Redistributions of source code must retain the above copyright notice,
+ *	   this list of conditions and the following disclaimer.
+ *	2. Redistributions in binary form must reproduce the above copyright notice,
+ *	   this list of conditions and the following disclaimer in the documentation
+ *	   and/or other materials provided with the distribution.
+ *	3. Neither the name of the developer nor the names of its contributors may
+ *	   be used to endorse or promote products derived from this software without
+ *	   specific prior written permission.
+ *	4. Redistributions in any form must be accompanied by information on how to
+ *	   obtain complete source code for the software and any accompanying
+ *	   software that uses the software. The source code must either be included
+ *	   in the distribution or be available for no more than the cost of
+ *	   distribution plus a nominal fee, and must be freely redistributable
+ *	   under reasonable conditions. For an executable file, complete source
+ *	   code means the source code for all modules it contains. It does not
+ *	   include source code for modules or files that typically accompany the
+ *	   major components of the operating system on which the executable file
+ *	   runs.
+ *	
+ *	THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ *	AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ *	IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ *	ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ *	LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *	CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ *	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ *	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ *	POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "bots.h"
+
+void InitStringTable();
+unsigned int PushToStringTable (char* s);
+unsigned int CountStringTable ();
+
+#ifndef __STRINGTABLE_CXX__
+extern
+#endif
+char g_StringTable[MAX_LIST_STRINGS][MAX_STRING_LENGTH];
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/variables.cxx	Fri Jan 10 16:11:49 2014 +0200
@@ -0,0 +1,106 @@
+/*
+ *	botc source code
+ *	Copyright (C) 2012 Santeri `Dusk` Piippo
+ *	All rights reserved.
+ *	
+ *	Redistribution and use in source and binary forms, with or without
+ *	modification, are permitted provided that the following conditions are met:
+ *	
+ *	1. Redistributions of source code must retain the above copyright notice,
+ *	   this list of conditions and the following disclaimer.
+ *	2. Redistributions in binary form must reproduce the above copyright notice,
+ *	   this list of conditions and the following disclaimer in the documentation
+ *	   and/or other materials provided with the distribution.
+ *	3. Neither the name of the developer nor the names of its contributors may
+ *	   be used to endorse or promote products derived from this software without
+ *	   specific prior written permission.
+ *	4. Redistributions in any form must be accompanied by information on how to
+ *	   obtain complete source code for the software and any accompanying
+ *	   software that uses the software. The source code must either be included
+ *	   in the distribution or be available for no more than the cost of
+ *	   distribution plus a nominal fee, and must be freely redistributable
+ *	   under reasonable conditions. For an executable file, complete source
+ *	   code means the source code for all modules it contains. It does not
+ *	   include source code for modules or files that typically accompany the
+ *	   major components of the operating system on which the executable file
+ *	   runs.
+ *	
+ *	THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ *	AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ *	IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ *	ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ *	LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *	CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ *	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ *	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ *	POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#define __VARIABLES_CXX__
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "common.h"
+#include "array.h"
+#include "bots.h"
+#include "botcommands.h"
+#include "objwriter.h"
+#include "stringtable.h"
+#include "variables.h"
+#include "scriptreader.h"
+
+array<ScriptVar> g_GlobalVariables;
+array<ScriptVar> g_LocalVariables;
+
+// ============================================================================
+// Tries to declare a new global-scope variable. Returns pointer
+// to new global variable, NULL if declaration failed.
+ScriptVar* DeclareGlobalVariable (ScriptReader* r, type_e type, str name) {
+	// Unfortunately the VM does not support string variables so yeah.
+	if (type == TYPE_STRING)
+		r->ParserError ("variables cannot be string\n");
+	
+	// Check that the variable is valid
+	if (FindCommand (name))
+		r->ParserError ("name of variable-to-be `%s` conflicts with that of a command", name.chars());
+	
+	if (IsKeyword (name))
+		r->ParserError ("name of variable-to-be `%s` is a keyword", name.chars());
+	
+	if (g_GlobalVariables.size() >= MAX_SCRIPT_VARIABLES)
+		r->ParserError ("too many global variables!");
+	
+	for (uint i = 0; i < g_GlobalVariables.size(); i++)
+		if (g_GlobalVariables[i].name == name)
+			r->ParserError ("attempted redeclaration of global variable `%s`", name.chars());
+	
+	ScriptVar g;
+	g.index = g_GlobalVariables.size();
+	g.name = name;
+	g.statename = "";
+	g.value = 0;
+	g.type = type;
+	
+	g_GlobalVariables << g;
+	return &g_GlobalVariables[g.index];
+}
+
+// ============================================================================
+// Find a global variable by name
+ScriptVar* FindGlobalVariable (str name) {
+	for (uint i = 0; i < g_GlobalVariables.size(); i++) {
+		ScriptVar* g = &g_GlobalVariables[i];
+		if (g->name == name)
+			return g;
+	}
+	
+	return NULL;
+}
+
+// ============================================================================
+// Count all declared global variables
+uint CountGlobalVars () {
+	return g_GlobalVariables.size();
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/variables.h	Fri Jan 10 16:11:49 2014 +0200
@@ -0,0 +1,66 @@
+/*
+ *	botc source code
+ *	Copyright (C) 2012 Santeri `Dusk` Piippo
+ *	All rights reserved.
+ *	
+ *	Redistribution and use in source and binary forms, with or without
+ *	modification, are permitted provided that the following conditions are met:
+ *	
+ *	1. Redistributions of source code must retain the above copyright notice,
+ *	   this list of conditions and the following disclaimer.
+ *	2. Redistributions in binary form must reproduce the above copyright notice,
+ *	   this list of conditions and the following disclaimer in the documentation
+ *	   and/or other materials provided with the distribution.
+ *	3. Neither the name of the developer nor the names of its contributors may
+ *	   be used to endorse or promote products derived from this software without
+ *	   specific prior written permission.
+ *	4. Redistributions in any form must be accompanied by information on how to
+ *	   obtain complete source code for the software and any accompanying
+ *	   software that uses the software. The source code must either be included
+ *	   in the distribution or be available for no more than the cost of
+ *	   distribution plus a nominal fee, and must be freely redistributable
+ *	   under reasonable conditions. For an executable file, complete source
+ *	   code means the source code for all modules it contains. It does not
+ *	   include source code for modules or files that typically accompany the
+ *	   major components of the operating system on which the executable file
+ *	   runs.
+ *	
+ *	THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ *	AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ *	IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ *	ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ *	LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *	CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ *	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ *	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ *	POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __VARIABLES_H__
+#define __VARIABLES_H__
+#include "str.h"
+#include "scriptreader.h"
+
+struct ScriptVar {
+	str name;
+	str statename;
+	type_e type;
+	int value;
+	unsigned int index;
+};
+
+extern array<ScriptVar> g_GlobalVariables;
+extern array<ScriptVar> g_LocalVariables;
+
+#define ITERATE_GLOBAL_VARS(u) \
+	for (u = 0; u < MAX_SCRIPT_VARIABLES; u++)
+#define ITERATE_SCRIPT_VARS(g) \
+	for (g = g_ScriptVariable; g != NULL; g = g->next)
+
+ScriptVar* DeclareGlobalVariable (ScriptReader* r, type_e type, str name);
+deprecated unsigned int CountGlobalVars ();
+ScriptVar* FindGlobalVariable (str name);
+
+#endif // __VARIABLES_H__
\ No newline at end of file
--- a/str.cxx	Wed Jan 02 23:57:46 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,426 +0,0 @@
-/*
- *	botc source code
- *	Copyright (C) 2012 Santeri `Dusk` Piippo
- *	All rights reserved.
- *	
- *	Redistribution and use in source and binary forms, with or without
- *	modification, are permitted provided that the following conditions are met:
- *	
- *	1. Redistributions of source code must retain the above copyright notice,
- *	   this list of conditions and the following disclaimer.
- *	2. Redistributions in binary form must reproduce the above copyright notice,
- *	   this list of conditions and the following disclaimer in the documentation
- *	   and/or other materials provided with the distribution.
- *	3. Neither the name of the developer nor the names of its contributors may
- *	   be used to endorse or promote products derived from this software without
- *	   specific prior written permission.
- *	4. Redistributions in any form must be accompanied by information on how to
- *	   obtain complete source code for the software and any accompanying
- *	   software that uses the software. The source code must either be included
- *	   in the distribution or be available for no more than the cost of
- *	   distribution plus a nominal fee, and must be freely redistributable
- *	   under reasonable conditions. For an executable file, complete source
- *	   code means the source code for all modules it contains. It does not
- *	   include source code for modules or files that typically accompany the
- *	   major components of the operating system on which the executable file
- *	   runs.
- *	
- *	THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- *	AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- *	IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- *	ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
- *	LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- *	CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- *	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- *	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- *	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- *	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- *	POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdarg.h>
-#include "array.h"
-#include "str.h"
-#include "common.h"
-
-#define ITERATE_STRING(u) \
-	for (unsigned int u = 0; u < strlen (text); u++)
-
-// ============================================================================
-// vdynformat: Try to write to a formatted string with size bytes first, if
-// that fails, double the size and keep recursing until it works.
-char* vdynformat (const char* c, va_list v, unsigned int size) {
-	char* buffer = new char[size];
-	int r = vsnprintf (buffer, size-1, c, v);
-	if (r > (int)size-1 || r < 0) {
-		delete buffer;
-		buffer = vdynformat (c, v, size*2);
-	}
-	return buffer;
-}
-
-// ============================================================================
-str::str () {
-	text = new char[1];
-	clear();
-	alloclen = strlen (text);
-}
-
-str::str (const char* c) {
-	text = new char[1];
-	clear ();
-	alloclen = strlen (text);
-	append (c);
-}
-
-str::str (char c) {
-	text = new char[1];
-	clear ();
-	alloclen = strlen (text);
-	append (c);
-}
-
-// ============================================================================
-void str::clear () {
-	delete text;
-	text = new char[1];
-	text[0] = '\0';
-	curs = 0;
-}
-
-unsigned int str::len () {return strlen(text);}
-
-// ============================================================================
-void str::resize (unsigned int len) {
-	unsigned int oldlen = strlen (text);
-	char* oldtext = new char[oldlen];
-	strncpy (oldtext, text, oldlen);
-	
-	delete text;
-	text = new char[len+1];
-	for (unsigned int u = 0; u < len+1; u++)
-		text[u] = 0;
-	strncpy (text, oldtext, len);
-	
-	alloclen = len;
-}
-
-// ============================================================================
-void str::dump () {
-	for (unsigned int u = 0; u <= alloclen; u++)
-		printf ("\t%u. %u (%c)\n", u, text[u], text[u]);
-}
-
-// ============================================================================
-// Adds a new character at the end of the string.
-void str::append (char c) {
-	// Out of space, thus resize
-	if (curs == alloclen)
-		resize (alloclen+1);
-	text[curs] = c;
-	curs++;
-}
-
-void str::append (const char* c) {
-	resize (alloclen + strlen (c));
-	
-	for (unsigned int u = 0; u < strlen (c); u++) {
-		if (c[u] != 0)
-			append (c[u]);
-	}
-}
-
-void str::append (str c) {
-	append (c.chars());
-}
-
-// ============================================================================
-void str::appendformat (const char* c, ...) {
-	va_list v;
-	
-	va_start (v, c);
-	char* buf = vdynformat (c, v, 256);
-	va_end (v);
-	
-	append (buf);
-}
-
-void str::appendformat (str c, ...) {
-	va_list v;
-	
-	va_start (v, c);
-	char* buf = vdynformat (c.chars(), v, 256);
-	va_end (v);
-	
-	append (buf);
-}
-
-// ============================================================================
-char* str::chars () {
-	return text;
-}
-
-// ============================================================================
-unsigned int str::first (const char* c, unsigned int a) {
-	unsigned int r = 0;
-	unsigned int index = 0;
-	for (; a < alloclen; a++) {
-		if (text[a] == c[r]) {
-			if (r == 0)
-				index = a;
-			
-			r++;
-			if (r == strlen (c))
-				return index;
-		} else {
-			if (r != 0) {
-				// If the string sequence broke at this point, we need to
-				// check this character again, for a new sequence just
-				// might start right here.
-				a--;
-			}
-			
-			r = 0;
-		}
-	}
-	
-	return len ();
-}
-
-// ============================================================================
-unsigned int str::last (const char* c, int a) {
-	if (a == -1)
-		a = len();
-	
-	int max = strlen (c)-1;
-	
-	int r = max;
-	for (; a >= 0; a--) {
-		if (text[a] == c[r]) {
-			r--;
-			if (r == -1)
-				return a;
-		} else {
-			if (r != max)
-				a++;
-			
-			r = max;
-		}
-	}
-	
-	return len ();
-}
-
-// ============================================================================
-str str::substr (unsigned int a, unsigned int b) {
-	if (a > len()) a = len();
-	if (b > len()) b = len();
-	
-	if (b == a)
-		return "";
-	
-	if (b < a) {
-		printf ("str::substr: indices %u and %u given, should be the other way around, swapping..\n", a, b);
-		
-		// Swap the variables
-		unsigned int c = a;
-		a = b;
-		b = c;
-	}
-	
-	char* s = new char[b-a];
-	strncpy (s, text+a, b-a);
-	return str(s);
-}
-
-// ============================================================================
-void str::remove (unsigned int idx, unsigned int dellen) {
-	str s1 = substr (0, idx);
-	str s2 = substr (idx + dellen, len());
-	
-	clear();
-	
-	append (s1);
-	append (s2);
-}
-
-// ============================================================================
-void str::trim (int dellen) {
-	if (!dellen)
-		return;
-	
-	unsigned int delpos;
-	if (dellen > 0) {
-		delpos = len()-dellen;
-		text[delpos] = 0;
-		curs -= dellen;
-	} else {
-		str s = substr (-dellen, len());
-		clear();
-		append (s);
-	}
-}
-
-// ============================================================================
-void str::replace (const char* o, const char* n, unsigned int a) {
-	unsigned int idx;
-	
-	while ((idx = first (o, a)) != len()) {
-		str s1 = substr (0, idx);
-		str s2 = substr (idx + strlen (o), len());
-		
-		clear();
-		
-		append (s1);
-		append (n);
-		append (s2);
-	}
-}
-
-void str::insert (char* c, unsigned int pos) {
-	str s1 = substr (0, pos);
-	str s2 = substr (pos, len());
-	
-	clear();
-	append (s1);
-	append (c);
-	append (s2);
-}
-
-void str::reverse () {
-	char* tmp = new char[alloclen];
-	strcpy (tmp, text);
-	
-	clear();
-	curs = 0;
-	resize (alloclen);
-	for (int i = alloclen-1; i >= 0; i--)
-		append (tmp[i]);
-}
-
-void str::repeat (unsigned int n) {
-	char* tmp = new char[alloclen];
-	strcpy (tmp, text);
-	
-	for (; n > 0; n--)
-		append (tmp);
-}
-
-// ============================================================================
-bool str::isnumber () {
-	ITERATE_STRING (u) {
-		// Minus sign as the first character is allowed for negatives
-		if (!u && text[u] == '-')
-			continue;
-		
-		if (text[u] < '0' || text[u] > '9')
-			return false;
-	}
-	return true;
-}
-
-// ============================================================================
-bool str::isword () {
-	ITERATE_STRING (u) {
-		// lowercase letters
-		if (text[u] >= 'a' || text[u] <= 'z')
-			continue;
-		
-		// uppercase letters
-		if (text[u] >= 'A' || text[u] <= 'Z')
-			continue;
-		
-		return false;
-	}
-	return true;
-}
-
-// ============================================================================
-int str::compare (const char* c) {
-	return strcmp (text, c);
-}
-
-int str::compare (str c) {
-	return compare (c.chars());
-}
-
-int str::icompare (const char* c) {
-	return icompare (str ((char*)c));
-}
-
-int str::icompare (str b) {
-	return strcmp (tolower().chars(), b.tolower().chars());
-}
-
-// ============================================================================
-str str::tolower () {
-	str n = text;
-	
-	for (uint u = 0; u < len(); u++) {
-		if (n[u] > 'A' && n[u] < 'Z')
-			n.text[u] += ('a' - 'A');
-	}
-	
-	return n;
-}
-
-// ============================================================================
-str str::toupper () {
-	str n = text;
-	
-	for (uint u = 0; u < len(); u++) {
-		if (n[u] > 'a' && n[u] < 'z')
-			n.text[u] -= ('A' - 'a');
-	}
-	
-	return n;
-}
-
-// ============================================================================
-unsigned int str::count (char* c) {
-	unsigned int r = 0;
-	unsigned int tmp = 0;
-	ITERATE_STRING (u) {
-		if (text[u] == c[r]) {
-			r++;
-			if (r == strlen (c)) {
-				r = 0;
-				tmp++;
-			}
-		} else {
-			if (r != 0)
-				u--;
-			r = 0;
-		}
-	}
-	
-	return tmp;
-}
-
-// ============================================================================
-array<str> str::split (str del) {
-	array<str> res;
-	unsigned int a = 0;
-	
-	// Find all separators and store the text left to them.
-	while (1) {
-		unsigned int b = first (del, a);
-		
-		if (b == len())
-			break;
-		
-		res.push (substr (a, b));
-		a = b + strlen (del);
-	}
-	
-	// Add the string at the right of the last separator
-	res.push (substr (a, len()));
-	return res;
-}
-
-array<str> str::operator/ (str splitstring) {return split(splitstring);}
-array<str> str::operator/ (char* splitstring) {return split(splitstring);}
-array<str> str::operator/ (const char* splitstring) {return split(splitstring);}
\ No newline at end of file
--- a/str.h	Wed Jan 02 23:57:46 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,233 +0,0 @@
-/*
- *	botc source code
- *	Copyright (C) 2012 Santeri `Dusk` Piippo
- *	All rights reserved.
- *	
- *	Redistribution and use in source and binary forms, with or without
- *	modification, are permitted provided that the following conditions are met:
- *	
- *	1. Redistributions of source code must retain the above copyright notice,
- *	   this list of conditions and the following disclaimer.
- *	2. Redistributions in binary form must reproduce the above copyright notice,
- *	   this list of conditions and the following disclaimer in the documentation
- *	   and/or other materials provided with the distribution.
- *	3. Neither the name of the developer nor the names of its contributors may
- *	   be used to endorse or promote products derived from this software without
- *	   specific prior written permission.
- *	4. Redistributions in any form must be accompanied by information on how to
- *	   obtain complete source code for the software and any accompanying
- *	   software that uses the software. The source code must either be included
- *	   in the distribution or be available for no more than the cost of
- *	   distribution plus a nominal fee, and must be freely redistributable
- *	   under reasonable conditions. For an executable file, complete source
- *	   code means the source code for all modules it contains. It does not
- *	   include source code for modules or files that typically accompany the
- *	   major components of the operating system on which the executable file
- *	   runs.
- *	
- *	THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- *	AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- *	IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- *	ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
- *	LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- *	CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- *	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- *	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- *	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- *	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- *	POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef __STR_H__
-#define __STR_H__
-
-template<class T> class array;
-
-char* vdynformat (const char* c, va_list v, unsigned int size);
-
-#define SCCF_NUMBER	1<<0
-#define SCCF_WORD	1<<1
-
-// Dynamic string object, allocates memory when needed and
-// features a good bunch of manipulation methods
-class str {
-private:
-	// The actual message
-	char* text;
-	
-	// Where will append() place new characters?
-	unsigned int curs;
-	
-	// Allocated length
-	unsigned int alloclen;
-	
-	// Resize the text buffer to len characters
-	void resize (unsigned int len);
-public:
-	// ======================================================================
-	// CONSTRUCTORS
-	str ();
-	str (const char* c);
-	str (char c);
-	
-	// ======================================================================
-	// METHODS
-	
-	// Empty the string
-	void clear ();
-	
-	// Length of the string
-	unsigned int len ();
-	
-	// The char* form of the string
-	char* chars ();
-	
-	// Dumps the character table of the string
-	void dump ();
-	
-	// Appends text to the string
-	void append (char c);
-	void append (const char* c);
-	void append (str c);
-	
-	// Appends formatted text to the string.
-	void appendformat (const char* c, ...);
-	void appendformat (str c, ...);
-	
-	// Returns the first occurrence of c in the string, optionally starting
-	// from a certain position rather than the start.
-	unsigned int first (const char* c, unsigned int a = 0);
-	
-	// Returns the last occurrence of c in the string, optionally starting
-	// from a certain position rather than the end.
-	unsigned int last (const char* c, int a = -1);
-	
-	// Returns a substring of the string, from a to b.
-	str substr (unsigned int a, unsigned int b);
-	
-	// Replace a substring with another substring.
-	void replace (const char* o, const char* n, unsigned int a = 0);
-	
-	// Removes a given index from the string, optionally more characters than just 1.
-	void remove (unsigned int idx, unsigned int dellen=1);
-	
-	void trim (int dellen);
-	
-	// Inserts a substring into a certain position.
-	void insert (char* c, unsigned int pos);
-	
-	// Reverses the string.
-	void reverse ();
-	
-	// Repeats the string a given amount of times.
-	void repeat (unsigned int n);
-	
-	// Is the string a number?
-	bool isnumber ();
-	
-	// Is the string a word, i.e consists only of alphabetic letters?
-	bool isword ();
-	
-	// Convert string to lower case
-	str tolower ();
-	
-	// Convert string to upper case
-	str toupper ();
-	
-	// Compare this string with another
-	int compare (const char* c);
-	int compare (str c);
-	int icompare (str c);
-	int icompare (const char* c);
-	
-	// Counts the amount of substrings in the string
-	unsigned int count (char* s);
-	
-	array<str> split (str del);
-	
-	// ======================================================================
-	// OPERATORS
-	str operator+ (str& c) {
-		append (c);
-		return *this;
-	}
-	
-	str& operator+= (char c) {
-		append (c);
-		return *this;
-	}
-	
-	str& operator+= (const char* c) {
-		append (c);
-		return *this;
-	}
-	
-	str& operator+= (const str c) {
-		append (c);
-		return *this;
-	}
-	
-	str operator* (const int repcount) {
-		repeat (repcount);
-		return *this;
-	}
-	
-	str& operator*= (const int repcount) {
-		repeat (repcount);
-		return *this;
-	}
-	
-	str operator- (const int trimcount) {
-		trim (trimcount);
-		return *this;
-	}
-	
-	str& operator-= (const int trimcount) {
-		trim (trimcount);
-		return *this;
-	}
-	
-	array<str> operator/ (str splitstring);
-	array<str> operator/ (char* splitstring);
-	array<str> operator/ (const char* splitstring);
-	
-	str operator+ () {
-		return toupper ();
-	}
-	
-	str operator- () {
-		return tolower ();
-	}
-	
-	str operator! () {
-		reverse ();
-		return *this;
-	}
-	
-#define DEFINE_OPERATOR_TYPE(OPER, TYPE) \
-	bool operator OPER (TYPE other) {return compare(other) OPER 0;}
-#define DEFINE_OPERATOR(OPER) \
-	DEFINE_OPERATOR_TYPE (OPER, str) \
-	DEFINE_OPERATOR_TYPE (OPER, char*) \
-	DEFINE_OPERATOR_TYPE (OPER, const char*)
-	
-	DEFINE_OPERATOR (==)
-	DEFINE_OPERATOR (!=)
-	DEFINE_OPERATOR (>)
-	DEFINE_OPERATOR (<)
-	DEFINE_OPERATOR (>=)
-	DEFINE_OPERATOR (<=)
-	
-	char operator [] (unsigned int pos) {
-		return text[pos];
-	}
-	
-	operator char* () const {
-		return text;
-	}
-	
-	operator int () const {return atoi(text);}
-	operator unsigned int () const {return atoi(text);}
-};
-
-#endif // __STR_H__
\ No newline at end of file
--- a/stringtable.cxx	Wed Jan 02 23:57:46 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,104 +0,0 @@
-/*
- *	botc source code
- *	Copyright (C) 2012 Santeri `Dusk` Piippo
- *	All rights reserved.
- *	
- *	Redistribution and use in source and binary forms, with or without
- *	modification, are permitted provided that the following conditions are met:
- *	
- *	1. Redistributions of source code must retain the above copyright notice,
- *	   this list of conditions and the following disclaimer.
- *	2. Redistributions in binary form must reproduce the above copyright notice,
- *	   this list of conditions and the following disclaimer in the documentation
- *	   and/or other materials provided with the distribution.
- *	3. Neither the name of the developer nor the names of its contributors may
- *	   be used to endorse or promote products derived from this software without
- *	   specific prior written permission.
- *	4. Redistributions in any form must be accompanied by information on how to
- *	   obtain complete source code for the software and any accompanying
- *	   software that uses the software. The source code must either be included
- *	   in the distribution or be available for no more than the cost of
- *	   distribution plus a nominal fee, and must be freely redistributable
- *	   under reasonable conditions. For an executable file, complete source
- *	   code means the source code for all modules it contains. It does not
- *	   include source code for modules or files that typically accompany the
- *	   major components of the operating system on which the executable file
- *	   runs.
- *	
- *	THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- *	AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- *	IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- *	ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
- *	LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- *	CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- *	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- *	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- *	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- *	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- *	POSSIBILITY OF SUCH DAMAGE.
- */
-
-#define __STRINGTABLE_CXX__
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include "common.h"
-#include "bots.h"
-#include "stringtable.h"
-
-// ============================================================================
-// Initializes the string table
-void InitStringTable() {
-	// Zero out everything first.
-	for (unsigned int a = 0; a < MAX_LIST_STRINGS; a++)
-		for (unsigned int b = 0; b < MAX_STRING_LENGTH; b++)
-			g_StringTable[a][b] = 0;
-}
-
-// ============================================================================
-// Potentially adds a string to the table and returns the index of it.
-unsigned int PushToStringTable (char* s) {
-	// Must not be too long.
-	if (strlen (s) >= MAX_STRING_LENGTH)
-		error ("string `%s` too long (%d characters max)\n", s, strlen (s));
-	
-	// Find a free slot in the table. 
-	unsigned int a;
-	for (a = 0; a < MAX_LIST_STRINGS; a++) {
-		// String is already in the table, thus return it.
-		if (!strcmp (s, g_StringTable[a]))
-			return a;
-		
-		// String is empty, thus it's free.
-		if (!strlen (g_StringTable[a]))
-			break;
-	}
-	
-	// no free slots!
-	if (a == MAX_LIST_STRINGS)
-		error ("too many strings defined!\n");
-	
-	// Determine the length
-	size_t l1 = strlen (s);
-	size_t l2 = MAX_LIST_STRINGS - 1;
-	size_t len = (l1 < l2) ? l1 : l2;
-	
-	// Now, dump the string into the slot
-	strncpy (g_StringTable[a], s, len);
-	g_StringTable[a][len] = 0;
-	
-	return a;
-}
-
-// ============================================================================
-// Counts the amount of strings in the table.
-unsigned int CountStringTable () {
-	unsigned int count = 0;
-	for (unsigned int a = 0; a < MAX_LIST_STRINGS; a++) {
-		if (!strlen (g_StringTable[a]))
-			break;
-		else
-			count++;
-	}
-	return count;
-}
\ No newline at end of file
--- a/stringtable.h	Wed Jan 02 23:57:46 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,50 +0,0 @@
-/*
- *	botc source code
- *	Copyright (C) 2012 Santeri `Dusk` Piippo
- *	All rights reserved.
- *	
- *	Redistribution and use in source and binary forms, with or without
- *	modification, are permitted provided that the following conditions are met:
- *	
- *	1. Redistributions of source code must retain the above copyright notice,
- *	   this list of conditions and the following disclaimer.
- *	2. Redistributions in binary form must reproduce the above copyright notice,
- *	   this list of conditions and the following disclaimer in the documentation
- *	   and/or other materials provided with the distribution.
- *	3. Neither the name of the developer nor the names of its contributors may
- *	   be used to endorse or promote products derived from this software without
- *	   specific prior written permission.
- *	4. Redistributions in any form must be accompanied by information on how to
- *	   obtain complete source code for the software and any accompanying
- *	   software that uses the software. The source code must either be included
- *	   in the distribution or be available for no more than the cost of
- *	   distribution plus a nominal fee, and must be freely redistributable
- *	   under reasonable conditions. For an executable file, complete source
- *	   code means the source code for all modules it contains. It does not
- *	   include source code for modules or files that typically accompany the
- *	   major components of the operating system on which the executable file
- *	   runs.
- *	
- *	THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- *	AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- *	IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- *	ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
- *	LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- *	CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- *	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- *	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- *	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- *	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- *	POSSIBILITY OF SUCH DAMAGE.
- */
-
-#include "bots.h"
-
-void InitStringTable();
-unsigned int PushToStringTable (char* s);
-unsigned int CountStringTable ();
-
-#ifndef __STRINGTABLE_CXX__
-extern
-#endif
-char g_StringTable[MAX_LIST_STRINGS][MAX_STRING_LENGTH];
\ No newline at end of file
--- a/variables.cxx	Wed Jan 02 23:57:46 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,106 +0,0 @@
-/*
- *	botc source code
- *	Copyright (C) 2012 Santeri `Dusk` Piippo
- *	All rights reserved.
- *	
- *	Redistribution and use in source and binary forms, with or without
- *	modification, are permitted provided that the following conditions are met:
- *	
- *	1. Redistributions of source code must retain the above copyright notice,
- *	   this list of conditions and the following disclaimer.
- *	2. Redistributions in binary form must reproduce the above copyright notice,
- *	   this list of conditions and the following disclaimer in the documentation
- *	   and/or other materials provided with the distribution.
- *	3. Neither the name of the developer nor the names of its contributors may
- *	   be used to endorse or promote products derived from this software without
- *	   specific prior written permission.
- *	4. Redistributions in any form must be accompanied by information on how to
- *	   obtain complete source code for the software and any accompanying
- *	   software that uses the software. The source code must either be included
- *	   in the distribution or be available for no more than the cost of
- *	   distribution plus a nominal fee, and must be freely redistributable
- *	   under reasonable conditions. For an executable file, complete source
- *	   code means the source code for all modules it contains. It does not
- *	   include source code for modules or files that typically accompany the
- *	   major components of the operating system on which the executable file
- *	   runs.
- *	
- *	THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- *	AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- *	IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- *	ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
- *	LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- *	CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- *	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- *	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- *	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- *	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- *	POSSIBILITY OF SUCH DAMAGE.
- */
-
-#define __VARIABLES_CXX__
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include "common.h"
-#include "array.h"
-#include "bots.h"
-#include "botcommands.h"
-#include "objwriter.h"
-#include "stringtable.h"
-#include "variables.h"
-#include "scriptreader.h"
-
-array<ScriptVar> g_GlobalVariables;
-array<ScriptVar> g_LocalVariables;
-
-// ============================================================================
-// Tries to declare a new global-scope variable. Returns pointer
-// to new global variable, NULL if declaration failed.
-ScriptVar* DeclareGlobalVariable (ScriptReader* r, type_e type, str name) {
-	// Unfortunately the VM does not support string variables so yeah.
-	if (type == TYPE_STRING)
-		r->ParserError ("variables cannot be string\n");
-	
-	// Check that the variable is valid
-	if (FindCommand (name))
-		r->ParserError ("name of variable-to-be `%s` conflicts with that of a command", name.chars());
-	
-	if (IsKeyword (name))
-		r->ParserError ("name of variable-to-be `%s` is a keyword", name.chars());
-	
-	if (g_GlobalVariables.size() >= MAX_SCRIPT_VARIABLES)
-		r->ParserError ("too many global variables!");
-	
-	for (uint i = 0; i < g_GlobalVariables.size(); i++)
-		if (g_GlobalVariables[i].name == name)
-			r->ParserError ("attempted redeclaration of global variable `%s`", name.chars());
-	
-	ScriptVar g;
-	g.index = g_GlobalVariables.size();
-	g.name = name;
-	g.statename = "";
-	g.value = 0;
-	g.type = type;
-	
-	g_GlobalVariables << g;
-	return &g_GlobalVariables[g.index];
-}
-
-// ============================================================================
-// Find a global variable by name
-ScriptVar* FindGlobalVariable (str name) {
-	for (uint i = 0; i < g_GlobalVariables.size(); i++) {
-		ScriptVar* g = &g_GlobalVariables[i];
-		if (g->name == name)
-			return g;
-	}
-	
-	return NULL;
-}
-
-// ============================================================================
-// Count all declared global variables
-uint CountGlobalVars () {
-	return g_GlobalVariables.size();
-}
\ No newline at end of file
--- a/variables.h	Wed Jan 02 23:57:46 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,66 +0,0 @@
-/*
- *	botc source code
- *	Copyright (C) 2012 Santeri `Dusk` Piippo
- *	All rights reserved.
- *	
- *	Redistribution and use in source and binary forms, with or without
- *	modification, are permitted provided that the following conditions are met:
- *	
- *	1. Redistributions of source code must retain the above copyright notice,
- *	   this list of conditions and the following disclaimer.
- *	2. Redistributions in binary form must reproduce the above copyright notice,
- *	   this list of conditions and the following disclaimer in the documentation
- *	   and/or other materials provided with the distribution.
- *	3. Neither the name of the developer nor the names of its contributors may
- *	   be used to endorse or promote products derived from this software without
- *	   specific prior written permission.
- *	4. Redistributions in any form must be accompanied by information on how to
- *	   obtain complete source code for the software and any accompanying
- *	   software that uses the software. The source code must either be included
- *	   in the distribution or be available for no more than the cost of
- *	   distribution plus a nominal fee, and must be freely redistributable
- *	   under reasonable conditions. For an executable file, complete source
- *	   code means the source code for all modules it contains. It does not
- *	   include source code for modules or files that typically accompany the
- *	   major components of the operating system on which the executable file
- *	   runs.
- *	
- *	THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- *	AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- *	IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- *	ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
- *	LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- *	CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- *	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- *	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- *	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- *	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- *	POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef __VARIABLES_H__
-#define __VARIABLES_H__
-#include "str.h"
-#include "scriptreader.h"
-
-struct ScriptVar {
-	str name;
-	str statename;
-	type_e type;
-	int value;
-	unsigned int index;
-};
-
-extern array<ScriptVar> g_GlobalVariables;
-extern array<ScriptVar> g_LocalVariables;
-
-#define ITERATE_GLOBAL_VARS(u) \
-	for (u = 0; u < MAX_SCRIPT_VARIABLES; u++)
-#define ITERATE_SCRIPT_VARS(g) \
-	for (g = g_ScriptVariable; g != NULL; g = g->next)
-
-ScriptVar* DeclareGlobalVariable (ScriptReader* r, type_e type, str name);
-deprecated unsigned int CountGlobalVars ();
-ScriptVar* FindGlobalVariable (str name);
-
-#endif // __VARIABLES_H__
\ No newline at end of file

mercurial