//***************************************************************************
//
//								ABLSYMT.CPP
//
//***************************************************************************

#include "MW4Headers.hpp"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#ifndef ABLGEN_H
#include "ablgen.h"
#endif

#ifndef ABLERR_H
#include "ablerr.h"
#endif

#ifndef ABLSYMT_H
#include "ablsymt.h"
#endif

#ifndef ABLSCAN_H
#include "ablscan.h"
#endif

#ifndef ABLENV_H
#include "ablenv.h"
#endif

#ifndef ABLHEAP_H
#include "ablheap.h"
#endif

#include "ablfuncs.hpp"

namespace ABL
{

//***************************************************************************

//----------
// EXTERNALS

extern long				level;		// current nesting/scope level
extern UserHeapPtr		AblSymTableHeap;

//--------
// GLOBALS

SymTableNodePtr		SymTableDisplay[MAX_NESTING_LEVEL];

ABLModulePtr		LibrariesUsed[MAX_LIBRARIES_USED];
long				NumLibrariesUsed = 0;

//------------------
// Pre-defined types
TypePtr				IntegerTypePtr;
TypePtr				CharTypePtr;
TypePtr				RealTypePtr;
TypePtr				BooleanTypePtr;

Type DummyType = {		// for erroneous type definitions
	0,
	FRM_NONE,
	0,
	NULL
};

//***************************************************************************
// MISC. (initially were macros)
//***************************************************************************

/*inline*/ void searchLocalSymTable (SymTableNodePtr& IdPtr) {

	IdPtr = searchSymTable(wordString, SymTableDisplay[level]);
}

//***************************************************************************

inline void searchThisSymTable (SymTableNodePtr& IdPtr, SymTableNodePtr thisTable) {

	IdPtr = searchSymTable(wordString, thisTable);
}

//***************************************************************************

/*inline*/ void searchAllSymTables (SymTableNodePtr& IdPtr) {

	IdPtr = searchSymTableDisplay(wordString);
}

//***************************************************************************

/*inline*/ void enterLocalSymTable (SymTableNodePtr& IdPtr) {

	IdPtr = enterSymTable(wordString, &SymTableDisplay[level]);
}

//***************************************************************************

inline void enterNameLocalSymTable (SymTableNodePtr& IdPtr, const char* name) {

	IdPtr = enterSymTable(name, &SymTableDisplay[level]);
}

//***************************************************************************

/*inline*/ void searchAndFindAllSymTables (SymTableNodePtr& IdPtr) {

	if ((IdPtr = searchSymTableDisplay(wordString)) == NULL) 
	{
		syntaxError(ABL_ERR_SYNTAX_UNDEFINED_IDENTIFIER);
		IdPtr = enterSymTable(wordString, &SymTableDisplay[level]);
		IdPtr->defn.key = DFN_UNDEFINED;
		IdPtr->typePtr = &DummyType;
	}
}

//***************************************************************************

/*inline*/ void searchAndEnterLocalSymTable (SymTableNodePtr& IdPtr) {

	if ((IdPtr = searchSymTable(wordString, SymTableDisplay[level])) == NULL)
		IdPtr = enterSymTable(wordString, &SymTableDisplay[level]);
	else
		syntaxError(ABL_ERR_SYNTAX_REDEFINED_IDENTIFIER);
}

//***************************************************************************

/*inline*/ void searchAndEnterThisTable (SymTableNodePtr& IdPtr, SymTableNodePtr thisTable) {

	if ((IdPtr = searchSymTable(wordString, thisTable)) == NULL)
		IdPtr = enterSymTable(wordString, &thisTable);
	else
		syntaxError(ABL_ERR_SYNTAX_REDEFINED_IDENTIFIER);
}

//***************************************************************************

inline SymTableNodePtr symTableSuccessor (SymTableNodePtr nodeX) {

	if (nodeX->right) {
		// return the treeMin...
		while (nodeX->left)
			nodeX = nodeX->left;
		return(nodeX);
	}
	
	SymTableNodePtr nodeY = nodeX->parent;
	while (nodeY && (nodeX == nodeY->right)) {
		nodeX = nodeY;
		nodeY = nodeY->parent;
	}
	return(nodeY);
}

//***************************************************************************
// TYPE management routines
//***************************************************************************

TypePtr createType (void) {

	TypePtr newType = (TypePtr)AblSymTableHeap->Malloc(sizeof(Type));
	if (!newType)
		ABL_Fatal(0, " ABL: Unable to AblStackHeap->malloc newType ");
	newType->numInstances = 1;
	newType->form = FRM_NONE;
	newType->size = 0;
	newType->typeIdPtr = NULL;

	return(newType);
}

//---------------------------------------------------------------------------

TypePtr setType (TypePtr type) {

	if (type)
		type->numInstances++;

	return(type);
}

//---------------------------------------------------------------------------

void clearType (TypePtr& type) {

	if (type) {
		type->numInstances--;
		if (type->numInstances == 0) {
			AblSymTableHeap->Free(type);
			type = NULL;
		}
	}
}

//***************************************************************************
// SYMBOL TABLE routines
//***************************************************************************

void recordLibraryUsed (SymTableNodePtr memberNodePtr) {

	//------------------------------------------------------------------
	// If the library already on our list, then don't bother. Otherwise,
	// add it to our list...
	ABLModulePtr library = memberNodePtr->library;
	for (long i = 0; i < NumLibrariesUsed; i++)
		if (LibrariesUsed[i] == library)
			return;

	//---------------------------------------------------
	// New library, so record it if we still have room...
	if (NumLibrariesUsed > MAX_LIBRARIES_USED)
		ABL_Fatal(0, " ABL: Too many libraries referenced from module ");

	LibrariesUsed[NumLibrariesUsed++] = library;
}

//***************************************************************************

SymTableNodePtr searchSymTable (const char* name, SymTableNodePtr nodePtr) {

	while (nodePtr) {
		long compareResult = strcmp(name, nodePtr->name);
		if (compareResult == 0)
			return(nodePtr);
		if (compareResult < 0)
			nodePtr = nodePtr->left;
		else
			nodePtr = nodePtr->right;
	}
	return(NULL);
}

//***************************************************************************

SymTableNodePtr searchLibrarySymTable (const char* name, SymTableNodePtr nodePtr) {

	//-------------------------------------------------------------
	// Since all libraries are at the symbol display 0-level, we'll
	// check the local symbol table of all libraries. WARNING: This
	// will find the FIRST instance of a symbol with that name,
	// so don't load two libraries with a similarly named function
	// or variable, otherwise you may not get the one you want
	// unless you explicitly reference the library you want
	// (e.g. testLib.fudge, rather than just fudge). This is WAY
	// inefficient compared to simply knowing the library we want,
	// so any ABL programmer that causes this function to be called
	// should be shot --gd 9/29/97

	if (nodePtr) {
		long compareResult = strcmp(name, nodePtr->name);
		if (compareResult == 0)
			return(nodePtr);
		else {
			if (nodePtr->library && (nodePtr->defn.key == DFN_MODULE)) {
				SymTableNodePtr memberNodePtr = searchSymTable(name, nodePtr->defn.info.routine.localSymTable);
				if (memberNodePtr)
					return(memberNodePtr);
			}
			SymTableNodePtr nodeFoundPtr = searchLibrarySymTable(name, nodePtr->left);
			if (nodeFoundPtr)
				return(nodeFoundPtr);
			nodeFoundPtr = searchLibrarySymTable(name, nodePtr->right);
			if (nodeFoundPtr)
				return(nodeFoundPtr);
		}
	}
	return(NULL);
}

//***************************************************************************

SymTableNodePtr searchLibrarySymTableDisplay (const char* name) {

	SymTableNodePtr nodePtr = searchLibrarySymTable(name, SymTableDisplay[0]);
	return(nodePtr);
}

//***************************************************************************

SymTableNodePtr searchSymTableDisplay (const char* name) {

	//---------------------------------------------------------------------
	// First check if this is an explicit library reference. If so, we need
	// to determine which library and which identifier in that library...
	char* separator = strchr(name, '.');
	SymTableNodePtr nodePtr = NULL;

	if (separator) {
		*separator = NULL;
		SymTableNodePtr libraryNodePtr = searchSymTable(name, SymTableDisplay[0]);
		if (!libraryNodePtr)
			return(NULL);
		//-------------------------------------
		// Now, search for the member symbol...
		char* memberName = separator + 1;
		SymTableNodePtr memberNodePtr = searchSymTable(memberName, libraryNodePtr->defn.info.routine.localSymTable);
		if (memberNodePtr)
			recordLibraryUsed(memberNodePtr);
		return(memberNodePtr);
		}
	else {	
		for (long i = level; i >= 0; i--) {
			SymTableNodePtr nodePtr = searchSymTable(name, SymTableDisplay[i]);
			if (nodePtr)
				return(nodePtr);
		}
		//------------------------------------------------------------
		// We haven't found it, so maybe it's from a library but just
		// is not explicitly called with the library name. Since all
		// libraries are at the symbol table's 0-level, we'll check
		// the local symbol table of all libraries. WARNING: This
		// will find the FIRST instance of a symbol with that name,
		// so don't load two libraries with a similarly named function
		// or variable, otherwise you may not get the one you want
		// unless you explicitly reference the library you want
		// (e.g. testLib.fudge, rather than just fudge)...
		nodePtr = searchLibrarySymTableDisplay(name);
		if (nodePtr)
			recordLibraryUsed(nodePtr);
	}

	return(nodePtr);
}

//***************************************************************************

SymTableNodePtr enterSymTable (const char* name, SymTableNodePtr* ptrToNodePtr) {

	//-------------------------------------
	// First, create the new symbol node...
	SymTableNodePtr newNode = (SymTableNodePtr)AblSymTableHeap->Malloc(sizeof(SymTableNode));
	if (!newNode)
		ABL_Fatal(0, " ABL: Unable to AblSymTableHeap->malloc symbol ");

	newNode->name = (char*)AblSymTableHeap->Malloc(strlen(name) + 1);
	if (!newNode->name)
		ABL_Fatal(0, " ABL: Unable to AblSymTableHeap->malloc symbol name ");
	strcpy(newNode->name, name);
	newNode->left = NULL;
	newNode->parent = NULL;
	newNode->right = NULL;
	newNode->next = NULL;
	newNode->info = NULL;
	newNode->defn.key = DFN_UNDEFINED;
	newNode->defn.info.data.varType = VAR_TYPE_NORMAL;
	newNode->defn.info.data.offset = 0;
	newNode->typePtr = NULL;
	newNode->level = (unsigned char) level;
	newNode->labelIndex = 0;

	//-------------------------------------
	// Find where to put this new symbol...
	SymTableNodePtr curNode = *ptrToNodePtr;
	SymTableNodePtr parentNode = NULL;
	while (curNode) {
		if (strcmp(name, curNode->name) < 0)
			ptrToNodePtr = &(curNode->left);
		else
			ptrToNodePtr = &(curNode->right);
		parentNode = curNode;
		curNode = *ptrToNodePtr;
	}
	newNode->parent = parentNode;
	*ptrToNodePtr = newNode;

	return(newNode);
}

//***************************************************************************

#if 0

SymTableNodePtr enterModuleInSymTable (char* name, SymTableNodePtr* ptrToNodePtr) {

	//-------------------------------------
	// First, create the new symbol node...
	SymTableNodePtr newNode = (SymTableNodePtr)AblSymTableHeap->malloc(sizeof(SymTableNode));
	newNode->name = (char*)AblSymTableHeap->malloc(strlen(name) + 1);
	strcpy(newNode->name, name);
	newNode->left = NULL;
	newNode->right = NULL;
	newNode->next = NULL;
	newNode->info = NULL;
	newNode->defn.key = DFN_UNDEFINED;
	newNode->typePtr = NULL;
	newNode->level = level;
	newNode->labelIndex = 0;

	//-------------------------------------
	// Find where to put this new symbol...
	SymTableNodePtr curNode = *ptrToNodePtr;
	while (curNode) {
		if (strcmp(name, curNode->name) < 0)
			ptrToNodePtr = &(curNode->left);
		else
			ptrToNodePtr = &(curNode->right);
		curNode = *ptrToNodePtr;
	}
	*ptrToNodePtr = newNode;

	return(newNode);
}

#endif

//***************************************************************************

SymTableNodePtr insertSymTable (SymTableNodePtr* tableRoot, SymTableNodePtr newNode) {

	newNode->left = NULL;
	newNode->parent = NULL;
	newNode->right = NULL;

	//------------------------------------
	// Find where to insert this symbol...
	SymTableNodePtr curNode = *tableRoot;
	SymTableNodePtr parentNode = NULL;
	while (curNode) {
		if (strcmp(newNode->name, curNode->name) < 0)
			tableRoot = &(curNode->left);
		else
			tableRoot = &(curNode->right);
		parentNode = curNode;
		curNode = *tableRoot;
	}
	newNode->parent = parentNode;
	*tableRoot = newNode;

	return(newNode);
}

//***************************************************************************

SymTableNodePtr extractSymTable (SymTableNodePtr* tableRoot, SymTableNodePtr nodeKill) {

	//------------------------------------------------------------------------
	// NOTE: While this routine extracts a node from the symbol table,
	// it does not account for other nodes in the table that may be pointing
	// to the now-extracted node. Currently, this is not a problem as this
	// routine is really just used to extract the module's Identifier at level
	// 0 in the SymTable Display. Do we want to eliminate the use of the
	// parent pointer, and just hardcode something that may be more efficient
	// for this level-0 special case?

	SymTableNodePtr nodeX = NULL;
	SymTableNodePtr nodeY = NULL;

	if ((nodeKill->left == NULL) || (nodeKill->right == NULL))
		nodeY = nodeKill;
	else
		nodeY = symTableSuccessor(nodeKill);
	
	if (nodeY->left)
		nodeX = nodeY->left;
	else
		nodeX = nodeY->right;

	if (nodeX)
		nodeX->parent = nodeY->parent;

	if (nodeY->parent == NULL)
		*tableRoot = nodeX;
	else if (nodeY == nodeY->parent->left)
		nodeY->parent->left = nodeX;
	else
		nodeY->parent->right = nodeX;

	if (nodeY != nodeKill) {
		//--------------------------------------
		// Copy y data to nodeKill's position...
		nodeKill->next = nodeY->next;
		nodeKill->name = nodeY->name;
		nodeKill->info = nodeY->info;
		memcpy(&nodeKill->defn, &nodeY->defn, sizeof(Definition));
		nodeKill->typePtr = nodeY->typePtr;
		nodeKill->level = nodeY->level;
		nodeKill->labelIndex = nodeY->labelIndex;
	}

	return(nodeY);
}

//***************************************************************************

void enterStandardRoutine (const char* name, RoutineKey routineKey, DefinitionType definitionKey, bool isOrder) {

	SymTableNodePtr routineIdPtr;
	enterNameLocalSymTable(routineIdPtr, name);
	
	routineIdPtr->defn.key = definitionKey;
	routineIdPtr->defn.info.routine.key = routineKey;
	routineIdPtr->defn.info.routine.isOrder = isOrder;
	routineIdPtr->defn.info.routine.params = NULL;
	routineIdPtr->defn.info.routine.localSymTable = NULL;
	routineIdPtr->library = NULL;
	routineIdPtr->typePtr = NULL;
}

//***************************************************************************

void enterScope (SymTableNodePtr symTableRoot) {

	if (++level >= MAX_NESTING_LEVEL) {
		STOP(("ABL syntax error #%d", ABL_ERR_SYNTAX_NESTING_TOO_DEEP));
	}
	SymTableDisplay[level] = symTableRoot;
}

//***************************************************************************

SymTableNodePtr exitScope (void) {

	return(SymTableDisplay[level--]);
}

//***************************************************************************

void initSymTable (void) {

	//---------------------------------
	// Init the level-0 symbol table...
	SymTableDisplay[0] = NULL;
	
	//----------------------------------------------------------------------
	// Set up the basic variable types as identifiers in the symbol table...
	SymTableNodePtr integerIdPtr;
	enterNameLocalSymTable(integerIdPtr, "integer");
	SymTableNodePtr charIdPtr;
	enterNameLocalSymTable(charIdPtr, "char");
	SymTableNodePtr realIdPtr;
	enterNameLocalSymTable(realIdPtr, "real");
	SymTableNodePtr booleanIdPtr;
	enterNameLocalSymTable(booleanIdPtr, "boolean");
	SymTableNodePtr falseIdPtr;
	enterNameLocalSymTable(falseIdPtr, "false");
	SymTableNodePtr trueIdPtr;
	enterNameLocalSymTable(trueIdPtr, "true");
	
	//------------------------------------------------------------------
	// Now, create the basic variable TYPEs, and point their identifiers
	// to their proper type definition...
	IntegerTypePtr = createType();
	if (!IntegerTypePtr)
		ABL_Fatal(0, " ABL: Unable to AblSymTableHeap->malloc Integer Type ");
	CharTypePtr = createType();
	if (!CharTypePtr)
		ABL_Fatal(0, " ABL: Unable to AblSymTableHeap->malloc Char Type ");
	RealTypePtr = createType();
	if (!RealTypePtr)
		ABL_Fatal(0, " ABL: Unable to AblSymTableHeap->malloc Real Type ");
	BooleanTypePtr = createType();
	if (!BooleanTypePtr)
		ABL_Fatal(0, " ABL: Unable to AblSymTableHeap->malloc Boolean Type ");

	integerIdPtr->defn.key = DFN_TYPE;
	integerIdPtr->typePtr = IntegerTypePtr;
	IntegerTypePtr->form = FRM_SCALAR;
	IntegerTypePtr->size = sizeof(long);
	IntegerTypePtr->typeIdPtr = integerIdPtr;

	charIdPtr->defn.key = DFN_TYPE;
	charIdPtr->typePtr = CharTypePtr;
	CharTypePtr->form = FRM_SCALAR;
	CharTypePtr->size = sizeof(char);
	CharTypePtr->typeIdPtr = charIdPtr;
	
	realIdPtr->defn.key = DFN_TYPE;
	realIdPtr->typePtr = RealTypePtr;
	RealTypePtr->form = FRM_SCALAR;
	RealTypePtr->size = sizeof(float);
	RealTypePtr->typeIdPtr = realIdPtr;

	booleanIdPtr->defn.key = DFN_TYPE;
	booleanIdPtr->typePtr = BooleanTypePtr;
	BooleanTypePtr->form = FRM_ENUM;
	BooleanTypePtr->size = sizeof(long);
	BooleanTypePtr->typeIdPtr = booleanIdPtr;

	//----------------------------------------------------
	// Set up the FALSE identifier for the boolean type...
	BooleanTypePtr->info.enumeration.max = 1;
	((TypePtr)(booleanIdPtr->typePtr))->info.enumeration.constIdPtr = falseIdPtr;
	falseIdPtr->defn.key = DFN_CONST;
	falseIdPtr->defn.info.constant.value.integer = 0;
	falseIdPtr->typePtr = BooleanTypePtr;		

	//----------------------------------------------------
	// Set up the TRUE identifier for the boolean type...
	falseIdPtr->next = trueIdPtr;
	trueIdPtr->defn.key = DFN_CONST;
	trueIdPtr->defn.info.constant.value.integer = 1;
	trueIdPtr->typePtr = BooleanTypePtr;		

	//-------------------------------------------
	// Set up the standard, built-in functions...


	AddSpecificABLFunction("return", RTN_RETURN,stdReturn,execStdReturn);
	AddSpecificABLFunction("print", RTN_PRINT,stdPrint,execStdPrint);
	AddSpecificABLFunction("concat", RTN_CONCAT,stdConcat,execStdConcat);
	AddSpecificABLFunction("abs", RTN_ABS, stdAbs,execStdAbs);
	AddSpecificABLFunction("random", RTN_RANDOM, stdRandom,execStdRandom);
	AddSpecificABLFunction("round", RTN_ROUND, stdRound,execStdRound);
	AddSpecificABLFunction("sqrt", RTN_SQRT, stdSqrt,execStdSqrt);
	AddSpecificABLFunction("trunc", RTN_TRUNC, stdTrunc,execStdTrunc);
	AddSpecificABLFunction("getmodulehandle", RTN_GETMODHANDLE, stdGetModHandle,execStdGetModHandle);
	AddSpecificABLFunction("getmodulename", RTN_GETMODNAME, stdGetModName,execStdGetModName);
	AddSpecificABLFunction("setmodulename", RTN_SETMODNAME, stdSetModName,execStdSetModName);
	AddSpecificABLFunction("setmaxloops", RTN_SETMAXLOOPS, stdSetMaxLoops,execStdSetMaxLoops);
	AddSpecificABLFunction("fatal", RTN_FATAL, stdFatal,execStdFatal);
	AddSpecificABLFunction("assert", RTN_ASSERT, stdAssert,execStdAssert);

	//-----------------------------------
	// MW4 specific extensions
	//-----------------------------------


	AddABLFunction("getplayer",ParseNoParamInteger,execgetPlayer);
	AddABLFunction("getself",ParseNoParamInteger ,execgetSelf);
	AddABLFunction("getplayervehicle",ParseOneIntegerInteger ,execgetPlayerVehicle);
	AddABLFunction("setentropymood",ParseTwoInteger ,execsetEntropyMood);
	AddABLFunction("settarget",ParseTwoInteger,execsetTarget);
	AddABLFunction("gettarget",ParseOneIntegerInteger,execgetTarget);
	AddABLFunction("whoshot",ParseOneIntegerInteger ,execwhoShot);
	AddABLFunction("whodestroyed",ParseOneIntegerInteger ,execwhoDestroyed);
	AddABLFunction("getnearestenemy",ParseOneIntegerInteger,execgetNearestEnemy);
	AddABLFunction("findobject",hbFindObject,execFindObject);
	AddABLFunction("findobjectexcept",hbFindObjectExcept,execFindObjectExcept);
	AddABLFunction("setcurmood",ParseTwoInteger ,execsetCurMood);
	AddABLFunction("gethp",ParseOneIntegerInteger ,execgetHP);
	AddABLFunction("getlocation",hbgetLocation,execgetLocation);
	AddABLFunction("getnearestpathpoint",hbgetNearestPathPoint ,execgetNearestPathPoint);
	AddABLFunction("getgreatestthreat",ParseTwoIntegerInteger ,execgetGreatestThreat);
	AddABLFunction("getleastthreat",ParseTwoIntegerInteger ,execgetLeastThreat);
	AddABLFunction("getmechtype",ParseOneIntegerInteger,execgetMechType);
	AddABLFunction("getalignment",ParseOneIntegerInteger ,execgetAlignment);
	AddABLFunction("setalignment",ParseTwoInteger ,execsetAlignment);
	AddABLFunction("getgunneryskill",ParseOneIntegerInteger,execgetGunnerySkill);
	AddABLFunction("getpilotskill",ParseOneIntegerInteger,execgetPilotSkill);
	AddABLFunction("setskilllevel",hbsetSkillLevel ,execsetSkillLevel);
	AddABLFunction("setattackthrottle",ParseTwoInteger,execSetAttackThrottle);
	AddABLFunction("getattackthrottle",ParseOneIntegerInteger,execGetAttackThrottle);
	AddABLFunction("setignorefriendlyfire",ParseIntegerBoolean,execSetIgnoreFriendlyFire);
	AddABLFunction("setfiringdelay",hbSetFiringDelay,execSetFiringDelay);
	AddABLFunction("setcombatleash",hbSetCombatLeash,execSetCombatLeash);
	AddABLFunction("setguitarget",ParseTwoInteger,execSetGUITarget);
	AddABLFunction("getguitarget",ParseOneIntegerInteger,execGetGUITarget);
	AddABLFunction("getzoomstate",ParseOneIntegerBoolean,execGetZoomState);
	AddABLFunction("setcrouchstate",ParseIntegerBoolean,execSetCrouchState);
	AddABLFunction("getteamnumber",ParseOneIntegerInteger,execGetTeamNumber);
	AddABLFunction("teamexists",ParseOneIntegerBoolean,execTeamExists);
	AddABLFunction("getgameparam",ParseOneIntegerInteger,execGetGameParam);
	AddABLFunction("setteamtracking",ParseTwoInteger,execSetTeamTracking);
	AddABLFunction("gettimer",ParseOneIntegerInteger ,execgetTimer);
	AddABLFunction("settimer",ParseTwoInteger,execsetTimer);
	AddABLFunction("playerorder",ParseOneIntegerInteger,execplayerOrder);
	AddABLFunction("getelitelevel",ParseOneIntegerInteger,execgetEliteLevel);
	AddABLFunction("geteliteskill",ParseOneIntegerInteger,execgetEliteLevel);
	AddABLFunction("setelitelevel",hbsetEliteLevel,execsetEliteLevel);
	AddABLFunction("clearmoveorder",ParseOneInteger,execclearMoveOrder);
	AddABLFunction("isshutdown",ParseOneIntegerBoolean,execIsShutdown);
	AddABLFunction("isshot",ParseOneIntegerBoolean,execisShot);
	AddABLFunction("iswithin",hbisWithin,execisWithin);
	AddABLFunction("isdead",ParseOneIntegerBoolean,execisDead);
	AddABLFunction("isequal",hbisEqual,execisEqual);
	AddABLFunction("islesser",hbisLesser,execisLesser);
	AddABLFunction("isgreater",hbisGreater ,execisGreater);
	AddABLFunction("equalid",ParseTwoIntegerBoolean ,execequalID);
	AddABLFunction("isrammed",ParseOneIntegerBoolean,execisRammed);
	AddABLFunction("whorammed",ParseOneIntegerInteger,execwhoRammed);
	AddABLFunction("cansee",ParseTwoIntegerBoolean,execcanSee);
	AddABLFunction("cantarget",ParseTwoIntegerBoolean,execcanTarget);
	AddABLFunction("battlevaluelesser",ParseOneIntegerBoolean,execbattleValueLesser);
	AddABLFunction("battleValuelesserid",ParseTwoIntegerBoolean,execbattleValueLesserID);
	AddABLFunction("timelesser",hbtimeLesser,exectimeLesser);
	AddABLFunction("timegreater",hbtimeGreater,exectimeGreater);
	AddABLFunction("rand",ParseTwoIntegerInteger ,execrand);
	AddABLFunction("playsound",ParseOneInteger ,execplaySound);
	AddABLFunction("playmusic",ParseTwoInteger ,execplayMusic);
	AddABLFunction("killmusic",ParseOneInteger ,execkillMusic);
	AddABLFunction("fadeinmusic",ParseThreeInteger ,execfadeInMusic);
	AddABLFunction("fadeoutmusic",ParseThreeInteger ,execfadeOutMusic);
	AddABLFunction("playsoundonce",ParseOneInteger ,execplaySoundOnce);
	AddABLFunction("killsound",ParseOneInteger,execkillSound);
	AddABLFunction("setaudiofxenabled",ParseOneBoolean,execSetAudioFXEnabled);
	AddABLFunction("playeffect",ParseOneInteger,execplayEffect);
	AddABLFunction("killeffect",ParseOneInteger,execkillEffect);

	AddABLFunction("playlancematesound",ParsePlayLancemateSound,execPlayLancemateSound);
	AddABLFunction("playvoiceover",ParsePlayLancemateSound,execPlayVoiceOver);
	AddABLFunction("playvoiceoveronce",ParsePlayLancemateSound,execPlayVoiceOverOnce);
	AddABLFunction("killvoiceovers",ParseNoParam,execKillVoiceOvers);
	AddABLFunction("isvoiceoverplaying",ParseNoParamBoolean,execIsVoiceOverPlaying);
	AddABLFunction("ismusicplaying",ParseNoParamBoolean,execIsMusicPlaying);
	AddABLFunction("startmusic",ParseStartMusic,execStartMusic);
	AddABLFunction("playbettysound",ParseOneInteger,execPlayBettySound);
	AddABLFunction("playteambettysound",ParseTwoInteger,execPlayTeamBettySound);
	AddABLFunction("startmusicall",ParseOneInteger,execStartMusicAll);
	AddABLFunction("teamsetnav",ParseTwoInteger,execTeamSetNav);
	AddABLFunction("specifytalker",ParseTwoInteger,execSpecifyTalker);
	AddABLFunction("navpointreached",ParseOneInteger,execNavPointReached);

	AddABLFunction("setchancelancemateseject",ParseOneInteger,execSetChanceLancematesEject);
	AddABLFunction("setchancelancematesokwhenejecting",ParseOneInteger,execSetChanceLancematesOKWhenEjecting);
	AddABLFunction("setchancelancematesinjuredwhenejecting",ParseOneInteger,execSetChanceLancematesInjuredWhenEjecting);
	AddABLFunction("reveallancemate",ParseString,execRevealLancemate);
	AddABLFunction("hidelancemate",ParseString,execHideLancemate);

	AddABLFunction("revealobjective",ParseOneInteger,execrevealObjective);
	AddABLFunction("hideobjective",ParseOneInteger,exechideObjective);
	AddABLFunction("failobjective",ParseOneInteger,execfailObjective);
	AddABLFunction("successobjective",ParseOneInteger,execsuccessObjective);
	AddABLFunction("failobjectiveall",ParseOneInteger,execfailObjectiveAll);
	AddABLFunction("successobjectiveall",ParseOneInteger,execsuccessObjectiveAll);
	AddABLFunction("checkobjectivecompletion",ParseOneIntegerInteger,execcheckObjectiveCompletion);
	AddABLFunction("isvisible",ParseOneIntegerBoolean,execisVisible);
	AddABLFunction("showallrevealedobjectives",ParseNoParam,execshowAllRevealedObjectives);
	AddABLFunction("endmission",ParseEndMission,execEndMission);
	AddABLFunction("ismissioncomplete",ParseStringBoolean,execIsMissionComplete);

	AddABLFunction("savegame",ParseNoParam,execsaveGame);

	AddABLFunction("revealnavpoint",ParseOneIntegerForRevealNavPoint,execrevealNavPoint);
	AddABLFunction("setnavpoint",ParseOneInteger,execsetNavPoint);
	AddABLFunction("isnavrevealed",ParseOneIntegerBoolean,execIsNavRevealed);
	AddABLFunction("hidenav",ParseOneInteger,execHideNav);
	AddABLFunction("setradarnav",ParseTwoInteger,execSetRadarNav);

	AddABLFunction("CreateHeatSphere",ParseFourInteger,execcreateHeatSphere);
	AddABLFunction("CreateInstantHeatSphere",ParseThreeInteger,execcreateInstantHeatSphere);
	AddABLFunction("CreateFogSphere",ParseThreeInteger,execcreateFogSphere);
	AddABLFunction("CreateRadarSphere",ParseFourInteger,execcreateRadarSphere);

	AddABLFunction("teleport",hbteleport,execteleport);
	AddABLFunction("teleportandlook",hbteleportAndLook,execteleportAndLook); // jcem
	AddABLFunction("teleporttohell",ParseOneInteger,execteleportToHell);
	AddABLFunction("damnthe",ParseOneInteger,execteleportToHell);
	AddABLFunction("playchatter",ParseOneInteger,execplayChatter);
	AddABLFunction("playchatterPriority",ParseTwoInteger,execplayChatterPriority);
	AddABLFunction("killchatter",ParseNoParam,execkillChatter);
	AddABLFunction("starttimer",ParseOneInteger,execstartTimer);
	AddABLFunction("killtimer",ParseOneInteger,execkillTimer);
	AddABLFunction("resettimer",ParseOneInteger,execresetTimer);
	AddABLFunction("pausetimer",hbpauseTimer,execpauseTimer);
	AddABLFunction("orderdie",ParseNoParam,execorderDie);
	AddABLFunction("ordermovelookout",ParseNoParam,execorderMoveLookOut);
	AddABLFunction("ordermoveto",hborderMoveTo,execorderMoveTo);
	AddABLFunction("ordermovetofree",hborderMoveTo,execorderMoveToFree);
	AddABLFunction("orderformationmove",hborderFormationMove,execorderFormationMove);
	AddABLFunction("orderformonspot",hborderFormOnSpot,execorderFormOnSpot);
	AddABLFunction("ordermovetorigid",hborderMoveTo,execorderMoveToRigid);
	AddABLFunction("ordermoveflee",ParseTwoIntegerInteger,execorderMoveFlee);
	AddABLFunction("ordermoveresumepatrol",hborderMoveResumePatrol,execorderMoveResumePatrol);
	AddABLFunction("ordermoveresumepatrolfree",hborderMoveResumePatrol,execorderMoveResumePatrolFree);
	AddABLFunction("ordermoveresumepatrolrigid",hborderMoveResumePatrol,execorderMoveResumePatrolRigid);
	AddABLFunction("ordermovefollow",hborderMoveFollow,execorderMoveFollow);
	AddABLFunction("ordermovesit",hborderMoveSit,execorderMoveSit);
	AddABLFunction("ordermovetolocpoint",hborderMoveToLocPoint,execorderMoveToLocPoint);
	AddABLFunction("ordermovetoobject",hborderMoveToObject,execorderMoveToObject);
	AddABLFunction("orderattack",hborderAttack,execorderAttack);
	AddABLFunction("orderattacktactic",hborderAttackTactic,execorderAttackTactic);
	AddABLFunction("orderattackbomb",ParseNoParam,execorderAttackBomb);
	AddABLFunction("orderstopattacking",ParseNoParam,execorderStopAttacking);
	AddABLFunction("ordershootpoint",hborderShootPoint,execorderShootPoint);
	AddABLFunction("lancematecommand",ParseTwoInteger,execlancemateCommand);
	AddABLFunction("enableaistats",ParseNoParam,execEnableAIStats);
	AddABLFunction("disableaistats",ParseNoParam,execDisableAIStats);
	AddABLFunction("enablemovelines",ParseNoParam,execEnableMoveLines);
	AddABLFunction("disablemovelines",ParseNoParam,execDisableMoveLines);
	AddABLFunction("enableglobalinvulnerable",ParseNoParam,execEnableGlobalInvulnerable);
	AddABLFunction("disableglobalinvulnerable",ParseNoParam,execDisableGlobalInvulnerable);
	AddABLFunction("enableinvulnerable",ParseOneInteger,execEnableInvulnerable);
	AddABLFunction("disableinvulnerable",ParseOneInteger,execDisableInvulnerable);
	AddABLFunction("destroy",ParseOneInteger,execDestroy);
	AddABLFunction("gosmenuitemexec",ParseString,execGOSMenuItemExec);
	AddABLFunction("gosmenuitemchecked",ParseStringBoolean,execGOSMenuItemChecked);
	AddABLFunction("settargetdesirability",ParseTwoInteger,execSetTargetDesirability);
	AddABLFunction("setisshotradius",ParseTwoInteger,execSetIsShotRadius);
	AddABLFunction("setsquadtargetingradius",ParseTwoInteger,execSetSquadTargetingRadius);
	AddABLFunction("setsearchlight",ParseIntegerBoolean,execSetSearchLight);
	AddABLFunction("setgroupai",ParseTwoInteger,execSetGroupAI);
	AddABLFunction("getlancemate",ParseOneIntegerInteger,execGetLancemate);
	AddABLFunction("notifygroupenemyspotted",ParseTwoInteger,execNotifyGroupEnemySpotted);
	AddABLFunction("tacticisfinished",ParseOneIntegerBoolean,execTacticIsFinished);
	AddABLFunction("groupalldead",ParseOneIntegerBoolean,execGroupAllDead);
	AddABLFunction("groupaddobject",ParseTwoInteger,execGroupAddObject);
	AddABLFunction("groupremoveobject",ParseTwoInteger,execGroupRemoveObject);
	AddABLFunction("groupnumdead",ParseOneIntegerInteger,execGroupNumDead);
	AddABLFunction("groupsize",ParseOneIntegerInteger,execGroupSize);
	AddABLFunction("groupcontainsobject",ParseTwoIntegerBoolean,execGroupContainsObject);
	AddABLFunction("groupgetfirstgroup",ParseOneIntegerInteger,execGroupGetFirstGroup);
	AddABLFunction("groupgetfirstobject",ParseOneIntegerInteger,execGroupGetFirstObject);
	AddABLFunction("groupgetobject",ParseTwoIntegerInteger,execGroupGetObject);
	AddABLFunction("groupobjectid",ParseOneIntegerInteger,execGroupObjectID);
	AddABLFunction("groupallwithin",hbGroupAllWithin,execGroupAllWithin);
	AddABLFunction("teamobjectid",ParseOneIntegerInteger,execTeamObjectID);

	AddABLFunction("disableaijumping",ParseNoParam,execDisableAIJumping);

	AddABLFunction("play2danim",hbplay2DAnim,execplay2DAnim);	
	AddABLFunction("cinemastart",ParseNoParam,execcinemaStart);
	AddABLFunction("cinemaend",ParseNoParam,execcinemaEnd);
	AddABLFunction("cinemaskip",ParseNoParamBoolean,execcinemaskip);
	AddABLFunction("setcamerafootshake",ParseTwoInteger,execSetCameraFootShake);
	AddABLFunction("setinternalcamera", hbsetinternalcamera, execsetinternalcamera);
	AddABLFunction("setactivecamera", hbsetactivecamera, execsetactivecamera);
	AddABLFunction("setcameraFOV", hbsetcameraFOV, execsetcameraFOV);
	AddABLFunction("fadetoblack", hbfadetoblack, execfadetoblack);
	AddABLFunction("fadefromblack", hbfadefromblack, execfadefromblack);
	AddABLFunction("fadetowhite", hbfadetowhite, execfadetowhite);
	AddABLFunction("fadefromwhite", hbfadefromwhite, execfadefromwhite);
	AddABLFunction("camerafollowobject", hbcamerafollowobject, execcamerafollowobject);
	AddABLFunction("camerafollowpath", hbcamerafollowpath, execcamerafollowpath);
	AddABLFunction("cameraposition", hbcameraposition, execcameraposition);
	AddABLFunction("cameradetach", ParseNoParam, execcameradetach);
	AddABLFunction("cameraoffset", hbcameraoffset, execcameraoffset);
	AddABLFunction("overridecamerapitch", hboverridecamerapitch, execoverridecamerapitch);
	AddABLFunction("overridecamerayaw", hboverridecamerayaw, execoverridecamerayaw);
	AddABLFunction("overridecameraroll", hboverridecameraroll, execoverridecameraroll);
	AddABLFunction("resetcameraoverrides", ParseNoParam, execresetcameraoverrides);
	AddABLFunction("targetfollowobject", hbtargetfollowobject, exectargetfollowobject);
	AddABLFunction("targetfollowpath", hbtargetfollowpath, exectargetfollowpath);
	AddABLFunction("targetposition", hbtargetposition, exectargetposition);
	AddABLFunction("targetdetach", ParseNoParam, exectargetdetach);
	AddABLFunction("targetoffset", hbtargetoffset, exectargetoffset);

	AddABLFunction("setdebugstring",hbSetDebugString,execSetDebugString);
	AddABLFunction("startup",ParseOneInteger,execstartup);
	AddABLFunction("shutdown",ParseOneInteger,execshutDown);
	AddABLFunction("getmemoryinteger",ParseTwoIntegerInteger,execGetMemoryInteger);
	AddABLFunction("setmemoryinteger",hbSetMemoryInteger,execSetMemoryInteger);
	AddABLFunction("getmemoryreal",hbGetMemoryReal,execGetMemoryReal);
	AddABLFunction("setmemoryreal",hbSetMemoryReal,execSetMemoryReal);
	AddABLFunction("setglobaltrigger",ParseIntegerBoolean,execSetGlobalTrigger);
	AddABLFunction("getglobaltrigger",ParseOneIntegerBoolean,execGetGlobalTrigger);
	AddABLFunction("setsensorvisibility",ParseIntegerBoolean,execSetSensorVisibility);
	AddABLFunction("setautotargeting",ParseIntegerBoolean,execSetAutoTargeting);
	AddABLFunction("enableperweaponraycasting",ParseIntegerBoolean,execEnablePerWeaponRayCasting);
	AddABLFunction("ordertakeoff",ParseOneIntegerBoolean,execorderTakeOff);
	AddABLFunction("orderland",ParseNoParamBoolean,execorderLand);
	AddABLFunction("iswithinlocpoint",hbisWithinLoc,execisWithinLoc);
	AddABLFunction("playershooting",ParseTwoIntegerBoolean,execPlayerShooting);
	AddABLFunction("playerai",ParsePlayerAI,execPlayerAI);
	AddABLFunction("distance",hbDistance,execDistance);
	AddABLFunction("stopexecute",ParseOneInteger,execStopExecute);
	AddABLFunction("startexecute",ParseOneInteger,execStartExecute);
	AddABLFunction("setactivationdistance",ParseOneInteger,execSetActivationDistance);
	AddABLFunction("selfdestruct",ParseOneInteger,execSelfDestruct);
	AddABLFunction("flyby",ParseOneIntegerBoolean,execFlyBy);
	AddABLFunction("save",ParseOneInteger,execSave);
	AddABLFunction("helpmessage",ParseTwoInteger,execHelpMessage);
	AddABLFunction("getdifficulty",ParseNoParamInteger,execGetDifficulty);
	AddABLFunction("eject",ParseOneInteger,execEject);

	AddABLFunction("addmechinstancesalvage", ParseString, execAddMechInstanceSalvage);
	AddABLFunction("addcomponentsalvage", ParseStringInteger, execAddComponentSalvage);
	AddABLFunction("addweaponsalvage", ParseStringInteger, execAddWeaponSalvage);

	AddABLFunction ("markBuildingAsScorable", ParseOneInteger, execMarkBuildingAsScorable);

	AddABLFunction("jump",ParseTwoInteger,execJump);
	AddABLFunction("crouch",ParseOneInteger,execCrouch);
	AddABLFunction("fall",ParseTwoInteger,execFall);
	AddABLFunction("torsopitch",ParseIntegerReal,execTorsoPitch);
	AddABLFunction("torsoyaw",ParseIntegerReal,execTorsoYaw);
	AddABLFunction("setgimped",ParseIntegerBoolean,execSetGimped);
	AddABLFunction("setrotation",ParseTwoInteger,execSetRotation);
	AddABLFunction("sethelicoptersignoremissionbounds",ParseOneBoolean,execSetHelicoptersIgnoreMissionBounds);
	AddABLFunction("settorsocenteringenabled",ParseIntegerBoolean,execSetTorsoCenteringEnabled);
	AddABLFunction("setalwaysignoreobstacles",ParseOneBoolean,execSetAlwaysIgnoreObstacles);
	AddABLFunction("setignorefog",ParseIntegerBoolean,execSetIgnoreFog);

	AddABLFunction("setcompositingenabled",ParseOneBoolean,execSetCompositingEnabled);

	AddABLFunction("setsensormode",ParseTwoInteger,execSetSensorMode);
	AddABLFunction("getsensormode",ParseOneIntegerInteger,execGetSensorMode);

	AddABLFunction("setminspeed",ParseTwoInteger,execSetMinSpeed);

	AddABLFunction("addbucket",ParseAddBucket,execAddBucket);
	AddABLFunction("killbucket",ParseKillBucket,execKillBucket);
	AddABLFunction("showbucket",ParseShowBucket,execShowBucket);
	AddABLFunction("hidebucket",ParseHideBucket,execHideBucket);
	AddABLFunction("getbucketvalue",ParseGetBucketValue,execGetBucketValue);
	AddABLFunction("findbucketvalue",ParseFindBucketValue,execFindBucketValue);
	AddABLFunction("setbucketvalue",ParseSetBucketValue,execSetBucketValue);
	AddABLFunction("trackbucket",ParseTrackBucket,execTrackBucket);
	AddABLFunction("trackobjectbucket",ParseTrackObjectBucket,execTrackObjectBucket);
	AddABLFunction("findbucket",ParseFindBucket,execFindBucket);
	AddABLFunction("addcustombucketparameter",ParseTwoInteger,execAddCustomBucketParameter);
	AddABLFunction("setcustombucketname",ParseString,execSetCustomBucketName);
	AddABLFunction("setcustombucketnameindex",ParseOneInteger,execSetCustomBucketNameIndex);
	AddABLFunction("addpoints",ParseTwoInteger,execAddPoints);
	AddABLFunction("chatmessage",ParseString,execChatMessage);

	AddABLFunction("attachflag",ParseTwoInteger,execAttachFlag);
	AddABLFunction("dropflag",ParseOneInteger,execDropFlag);
// MSL 5.05 Return Flag Script Command
	AddABLFunction("returnflag",ParseOneInteger,execReturnFlag);
	AddABLFunction("deactiveflag",ParseTwoInteger,execDeactiveFlag);
	AddABLFunction("setmaxflagscarried",ParseTwoInteger,execSetMaxFlagsCarried);
	AddABLFunction("setflagdropreturntime",ParseOneInteger,execSetFlagDropReturnTime);
	AddABLFunction("setflagcapturereturntime",ParseOneInteger,execSetFlagCaptureReturnTime);
	AddABLFunction("setflagsenabled",ParseOneInteger,execSetFlagsEnabled);
	AddABLFunction("setflagcaptureenabled",ParseOneBoolean,execSetFlagCaptureEnabled);
	AddABLFunction("showflagsasnavpoints",ParseOneBoolean,execShowFlagsAsNavPoints);

	AddABLFunction("setviewmode",ParseOneInteger,execSetViewMode);
	AddABLFunction("getviewmode",ParseOneIntegerInteger,execGetViewMode);

	AddABLFunction("setinputtypeenabled",ParseIntegerBoolean,execSetInputTypeEnabled);
	AddABLFunction("sethudcomponentenabled",ParseIntegerBoolean,execSetHUDComponentEnabled);
	AddABLFunction("resetammo",ParseOneInteger,execResetAmmo);
	AddABLFunction("overrideheatoption",ParseOneBoolean,execOverrideHeatOption);

	AddABLFunction("setmissionbounds",ParseTwoInteger,execSetMissionBounds);

	AddABLFunction("respawn",ParseOneInteger,execRespawn);
	AddABLFunction("resetmission",ParseNoParam,execResetMission);

	AddABLFunction("getdamagerating",ParseOneIntegerInteger,execGetDamageRating);

	AddABLFunction("istargeted",ParseOneIntegerBoolean,execIsTargeted);
	AddABLFunction("lookingtoward",ParseOneIntegerBoolean,execLookingToward);
	AddABLFunction("firedweapongroup",ParseOneIntegerBoolean,execFiredWeaponGroup);
	AddABLFunction("issettonavpoint",ParseOneIntegerBoolean,execIsSetToNavPoint);

	AddABLFunction("orderdooropen",ParseNoParamBoolean,execorderDoorOpen);
	AddABLFunction("orderdoorclose",ParseNoParamBoolean,execorderDoorClose);
	AddABLFunction("boarddropship",ParseTwoIntegerBoolean,execboardDropShip);
	AddABLFunction("drop",ParseOneIntegerBoolean,execDrop);
	
	AddABLFunction("showtimer",ParseShowTimer,execShowTimer);
	AddABLFunction("showhelparrow",ParseShowHelpArrow,execShowHelpArrow);
	AddABLFunction("makecolor",ParseMakeColor,execMakeColor);
	AddABLFunction("sethelparrow",ParseSetHelpArrow,execSetHelpArrow);

	AddABLFunction("respawnmission",ParseNoParam,execRespawnMission);

	AddABLFunction("setdmgmodifier",ParseThreeInteger,execSetDmgModifier); // jcem
	AddABLFunction("restoreoriginalbounds",ParseNoParam,execRestoreOriginalBounds); // jcem
	AddABLFunction("setboundsfrompaths",ParseTwoInteger,execSetBoundsFromPaths); // jcem
	AddABLFunction("randselect",ParseThreeInteger,execRandSelect); // jcem
	AddABLFunction("respawnposition",ParseTwoInteger,execRespawnPosition); // jcem
    AddABLFunction("getcoop",ParseOneIntegerInteger,execGetCOOP); // jcem
    AddABLFunction("setcoop",ParseTwoIntegerInteger,execSetCOOP); // jcem
    AddABLFunction("gettime",ParseNoParamReal,execGetTime); // jcem
    AddABLFunction("gettimex",ParseNoParamReal,execGetTimeX); // jcem
    AddABLFunction("igettime",ParseNoParamInteger,execIGetTime); // jcem
    AddABLFunction("igettimex",ParseNoParamInteger,execIGetTimeX); // jcem
    AddABLFunction("playsoundstr",ParseString,execPlaySoundStr); // jcem
    
	AddABLFunction("logmaprespawn",ParseNoParamBoolean,execLogMapRespawn);
	AddABLFunction("logdefendingteam",ParseOneIntegerBoolean,execLogDefendingTeam);
	AddABLFunction("loghqdestroyed",ParseTwoIntegerBoolean,execLogHQDestroyed);
	AddABLFunction("logdefendtimeaward",ParseTwoIntegerBoolean,execLogDefendTimeAward);
}

//***************************************************************************

//***************************************************************************

}