#include "Script.hpp"
//===========================================================================//
// File:	 ScriptExpressions.hpp											 //
// Project:  GOSScript				                                         //
// Contents: Script Expression Evaluation									 //
//---------------------------------------------------------------------------//
// Date      Who    Modification                                             //
// 02/27/98  AG    Created													 //
//---------------------------------------------------------------------------//
// Copyright (C) 2000, Microsoft, Inc.										//
// All Rights reserved worldwide                                             //
// This unpublished sourcecode is PROPRIETARY and CONFIDENTIAL               //
//===========================================================================//
//

extern int g_scriptLineColor;
extern POSITION g_textXY;
extern CUBE g_textMargins;
extern gosEnum_TextWrap g_textWrapMode;
int GetNextExpression();
int OldGetKeyword();
extern OBJECT* pFocusedObject;
extern SCRIPT* pFocusedScript;
extern bool gIsDeclaration;

extern __int64 TimeScriptsExpression;
extern __int64 TimeScriptsCallbacks;

#if 1
extern BYTE g_bLeadByte;
#endif
//
// Faster float to long  (Always rounds to nearest)  ie: -2.7 goes to 3
//
inline long float2long( float fval )
{
	fval += 3 << 22;
	return ((*(long*)&fval)&0x007fffff) - 0x00400000;
}

extern int scriptLastKey;
extern REGVAR* pScriptRegisteredVariables;

extern VARIABLE* pLastVariableObject;
extern int pLastVariableObjectIndex;
extern int ScriptMouseButton1;	// for use as variable within scripts
extern int ScriptMouseButton2; // for use as variable within scripts
extern int ScriptMouseButton3; // for use as variable within scripts
extern int ScriptMouseButton4; // for use as variable within scripts
extern int ScriptMouseButton5; // for use as variable within scripts
extern int ScriptPointerDevice; // for use as variable within scripts

extern DWORD g_mailStack;
extern int g_scriptPostedInteger[][8];
extern OBJECT * g_scriptMailPoster[];

extern DWORD FontX;
extern DWORD FontY;

extern DWORD gosScript_localizationFile;

extern HGOSHEAP gScriptHeap[];
extern DWORD gCurrentHeapStackLevel;
extern HGOSHEAP ClientHeap;
extern BYTE LeadByteTable[];


BYTE KeyWordLength;
DWORD FindWordResult;
DWORD FindIndex;
DWORD FindHash;
bool checkingExistence = true;
long halfwayHouse;
//
// List of valid routine names (NOTE: must be all lowercase!)
//
char* Routines[]={
"getkeystate",
"getkeypressed",
"setvolume",
"setpanning",
"setfrequency",
"setproperties",
"getvolume",
"getpanning",
"getfrequency",
"getstatus",
"getsize",
"abs",
"getchar",
"char",
"getpixel",
"getheight",
"getwidth",
"callback",
"getmessage",
"gettime",
"gettimex",
"getprint3dwidth",
"getprint3dheight",
"getprint3dposx",
"getprint3dposy",
"gotfocus",
"makeint",
"exists",
"getresx",
"getresy",
"packcolor",
"list_top",
"list_bottom",
"list_next",
"list_prev",
"list_add",
"list_remove",
"list_length",
"list_empty",
"js_countdevices",
"js_getaxis",
"js_getbutton",
"js_countbuttons",
"js_isaxisvalid",
"mail",
"getctrlchar",
"querychar",
"launch",
"setpointer",
"js_setpolling",
"getkey",
"dblclick"
};

//
// List of valid keyword names (NOTE: must be all lowercase!)
//
char* Keywords[]={
"if",
"else",
"int",
"object",
"spew",
"for",
"while",
"do",
"break",
"continue",
"bitmap",
"font",
"sound",
"blit",
"position",
"play",
"loop",
"drawline",
"ldrawline",
"string",
"kill",
"print_position",
"print",
"print_bitmap",
"print_font",
"print_margins",
"colorkey",
"script_run",
"script_end",
"script_pause",
"script_continue",
"focus",
"unfocus",
"cube",
"movie",
"stop",
"gaf",
"setframe",
"bitmap_create",
"bitmap_clear",
"bitmap_refresh",
"random",
"debug",
"pane",
"scale",
"rotate",
"origin",
"color",
"alphamode",
"render",
"pane_create",
"update",
"refresh",
"wrap",
"pass_on",
"wrapbyword",
"wrapbyletter",
"wrapnone",
"fill",
"execute",
"return",
"initialize",
"drawrect",
"drawframe",
"setpencolor",
"print3d_position",
"print3d_margins",
"print3d_attributes",
"font3d",
"print3d",
"clearzbuffer",
"textureheap",
"terminate",
"activate",
"deactivate",
"setresource",
"assign",
"ldrawframe",
"ldrawrect",
"lprint3d_margins",
"lprint3d_position",
"float",
"list",
"switch",
"case",
"default",
"js_getname",
"makeabsolute",
"getscriptinfo",
"setcaret",
"enableime",
"getclipboard",
"setclipboard",
"pause",
"continue",
"toggleime",
"precision"
};

//
// Predefined constants (NOTE: must be all lowercase!)
//
int ValueConstant[]={
BUTTON_FREE,
BUTTON_PRESSED,
BUTTON_HELD,
BUTTON_RELEASED,
BUTTON_CLICKED,
BUTTON_DCLICKED,
gos_Alpha_OneZero,
gos_Alpha_OneOne,
gos_Alpha_AlphaInvAlpha,
gos_Alpha_OneInvAlpha,
0,			// solid
1,			// alpha
2,			// keyed
2,			// colorkey (old legacy syntax)
3,			// volitile
4,			// nonvolitile
0,			// st_stream
1,			// st_cached
2,			// st_music
16,			// sf_loop
1,			// sf_in_hardware (sound flag)
2,			// sf_dyn_vol
8,			// sf_dyn_frq
4,			// sf_dyn_pan
0,			// NULL
1,			// status: playing
2,			// status: paused
3,			// status: stopped
4,			// status: looping
0,			// status: atend
0,			// false
1,			// true
KEY_ESCAPE,	// Keyboard keys
KEY_1,
KEY_2,
KEY_3,
KEY_4,
KEY_5,
KEY_6,
KEY_7,
KEY_8,
KEY_9,
KEY_0,
KEY_MINUS,
KEY_EQUALS,
KEY_BACK,
KEY_TAB,
KEY_Q,
KEY_W,
KEY_E,
KEY_R,
KEY_T,
KEY_Y,
KEY_U,
KEY_I,
KEY_O,
KEY_P,
KEY_LBRACKET,
KEY_RBRACKET,
KEY_RETURN,
KEY_LCONTROL,
KEY_A,
KEY_S,
KEY_D,
KEY_F,
KEY_G,
KEY_H,
KEY_J,
KEY_K,
KEY_L,
KEY_SEMICOLON,
KEY_APOSTROPHE,
KEY_GRAVE,
KEY_LSHIFT,
KEY_BACKSLASH,
KEY_Z,
KEY_X,
KEY_C,
KEY_V,
KEY_B,
KEY_N,
KEY_M,
KEY_COMMA,
KEY_PERIOD,
KEY_SLASH,
KEY_RSHIFT,
KEY_MULTIPLY,
KEY_LMENU,
KEY_SPACE,
KEY_CAPITAL,
KEY_F1,
KEY_F2,
KEY_F3,
KEY_F4,
KEY_F5,
KEY_F6,
KEY_F7,
KEY_F8,
KEY_F9,
KEY_F10,
KEY_NUMLOCK,
KEY_NUMPAD7,
KEY_NUMPAD8,
KEY_NUMPAD9,
KEY_SUBTRACT,
KEY_NUMPAD4,
KEY_NUMPAD5,
KEY_NUMPAD6,
KEY_ADD,
KEY_NUMPAD1,
KEY_NUMPAD2,
KEY_NUMPAD3,
KEY_NUMPAD0,
KEY_DECIMAL,
KEY_F11,
KEY_F12,
KEY_F13,
KEY_F14,
KEY_F15,
KEY_KANA,
KEY_CONVERT,
KEY_NOCONVERT,
KEY_YEN,
KEY_NUMPADEQUALS,
KEY_CIRCUMFLEX,
KEY_AT,
KEY_COLON,
KEY_UNDERLINE,
KEY_KANJI,
KEY_STOP,
KEY_AX,
KEY_UNLABELED,
KEY_NUMPADENTER,
KEY_RCONTROL,
KEY_NUMPADCOMMA,
KEY_DIVIDE,
KEY_SYSRQ,
KEY_RMENU,
KEY_HOME,
KEY_UP,
KEY_PRIOR,
KEY_LEFT,
KEY_RIGHT,
KEY_END,
KEY_DOWN,
KEY_NEXT,
KEY_INSERT,
KEY_DELETE,
KEY_LWIN,
KEY_RWIN,
KEY_APPS,
KEY_PAUSE,
0,				// justify left
1,				// justify right
2,				// justify center
3,				// justify all (horiz & vertical)
-1
};
//
// The string versions of the above enumlist (ValueConstant)
//
char* StringConstant[]={
"button_free",
"button_pressed",
"button_held",
"button_released",
"button_clicked",
"button_dclicked",
"am_alpha_onezero",
"am_alpha_oneone",
"am_alpha_alphainvalpha",
"am_alpha_oneinvalpha",
"solid",
"alpha",
"keyed",
"colorkey",
"volatile",
"nonvolatile",
"st_cached",
"st_streamed",
"st_music",
"sp_loop",
"sp_in_hardware",
"sp_dynamic_volume",
"sp_dynamic_frequency",
"sp_dynamic_panning",
"null",
"status_playing",
"status_paused",
"status_stopped",
"status_looping",
"status_atend",
"false",
"true",
"key_escape",
"key_1",
"key_2",
"key_3",
"key_4",
"key_5",
"key_6",
"key_7",
"key_8",
"key_9",
"key_0",
"key_minus",
"key_equals",
"key_back",
"key_tab",
"key_q",
"key_w",
"key_e",
"key_r",
"key_t",
"key_y",
"key_u",
"key_i",
"key_o",
"key_p",
"key_lbracket",
"key_rbracket",
"key_return",
"key_lcontrol",
"key_a",
"key_s",
"key_d",
"key_f",
"key_g",
"key_h",
"key_j",
"key_k",
"key_l",
"key_semicolon",
"key_apostrophe",
"key_grave",
"key_lshift",
"key_backslash",
"key_z",
"key_x",
"key_c",
"key_v",
"key_b",
"key_n",
"key_m",
"key_comma",
"key_period",
"key_slash",
"key_rshift",
"key_multiply",
"key_lmenu",
"key_space",
"key_capital",
"key_f1",
"key_f2",
"key_f3",
"key_f4",
"key_f5",
"key_f6",
"key_f7",
"key_f8",
"key_f9",
"key_f10",
"key_numlock",
"key_numpad7",
"key_numpad8",
"key_numpad9",
"key_subtract",
"key_numpad4",
"key_numpad5",
"key_numpad6",
"key_add",
"key_numpad1",
"key_numpad2",
"key_numpad3",
"key_numpad0",
"key_decimal",
"key_f11",
"key_f12",
"key_f13",
"key_f14",
"key_f15",
"key_kana",
"key_convert",
"key_noconvert",
"key_yen",
"key_numpadequals",
"key_circumflex",
"key_at",
"key_colon",
"key_underline",
"key_kanji",
"key_stop",
"key_ax",
"key_unlabeled",
"key_numpadenter",
"key_rcontrol",
"key_numpadcomma",
"key_divide",
"key_sysrq",
"key_rmenu",
"key_home",
"key_up",
"key_prior",
"key_left",
"key_right",
"key_end",
"key_down",
"key_next",
"key_insert",
"key_delete",
"key_lwin",
"key_rwin",
"key_apps",
"key_pause",
"just_left",
"just_right",
"just_center",
"just_all",
"from_application"
};








//
// Fast string search routine
//
// Flags:
//  Low byte    = Length
//  High byte   = 256=String, 512=Routine, 1024=Keywords
//  top 16 bits = Hash
//
typedef struct _FastString
{
	_FastString*	pNext;
	DWORD			Flags;
	char*			String;
	DWORD			Value;
} FastString;
//
// 4 bits of hash, 3 bits of length - index into this list
//
FastString* FastArray[128];





FastString* StringPool=0;

struct SVarDef // jcem
{
public:
	const char* m_pcszName;
	VAR_TYPE m_eType;
	void* m_pVar;
	VAR_SCOPE m_eScope;
//
	int m_nLen;
public:
	static VAR_TYPE FindVar(const SVarDef* pcVarDefs, int nVars);
};

VAR_TYPE SVarDef::FindVar(const SVarDef* pcVarDefs, int nVars)
{
	gosASSERT(pcVarDefs && (0 < nVars));
	const SVarDef* pcEnds = &pcVarDefs[nVars];
	while(pcVarDefs < pcEnds)
	{
		if (pcVarDefs->m_nLen <= 0) {
			*(int*)&pcVarDefs->m_nLen = strlen(pcVarDefs->m_pcszName);
			gosASSERT(0 < pcVarDefs->m_nLen);
		}
		gosASSERT(strlen(pcVarDefs->m_pcszName) == pcVarDefs->m_nLen);

		if (( memcmp( pLine, pcVarDefs->m_pcszName, pcVarDefs->m_nLen ) == 0 ) && (0==KeywordChar[pLine[pcVarDefs->m_nLen]])) {
			pLine += pcVarDefs->m_nLen;
			pLastVariable=(long*)pcVarDefs->m_pVar;
			gosASSERT(pLastVariable);

			LastVariableScope=pcVarDefs->m_eScope;
			return pcVarDefs->m_eType;
		}
		pcVarDefs++;
	}

	return VAR_UNKNOWN;
}
//
// Setup the strings to be searched
//
void InitFastString()
{
//
// Check that our keywords and routines match their enums
//
	gosASSERT( LAST_ROUTINE==(sizeof(Routines)/4) );
	gosASSERT( LAST_KEYWORD-3==(sizeof(Keywords)/4) );
//
// Allocate a FastString structure for each string
//
	StringPool=(FastString*)gos_Malloc(	(sizeof(Routines)/sizeof(char*) + sizeof(StringConstant)/sizeof(char*) + sizeof(Keywords)/sizeof(char*) ) * sizeof(FastString), gScriptHeap[0] );
	memset( FastArray, 0, sizeof(FastArray) );
	FastString* pThis=StringPool;
//
// Add 'StringConstant's
//
	for( int t0=0; t0<sizeof(StringConstant)/sizeof(char*); t0++ )
	{
//
// Get length and hash for string
//
		pThis->pNext=0;
		pThis->String=StringConstant[t0];
		pThis->Value=ValueConstant[t0];
		unsigned long Len=strlen(pThis->String);
		DWORD Hash=0;
		for( unsigned long t1=0; t1< Len; t1++ )
			Hash=(Hash<<3)+pThis->String[t1];
		pThis->Flags=(Hash<<16) + 256 + Len;
//
// Add to FastArray
//
		DWORD Index=((Hash&15)<<3)+(Len&7);
		if( FastArray[Index] )
		{
			pThis->pNext=FastArray[Index];
		}
		FastArray[Index]=pThis;
		pThis++;
	}
//
// Add 'Routines's
//
	for( t0=0; t0<sizeof(Routines)/sizeof(char*); t0++ )
	{
//
// Get length and hash for string
//
		pThis->pNext=0;
		pThis->String=Routines[t0];
		pThis->Value=t0;
		DWORD Len=strlen(pThis->String);
		DWORD Hash=0;
		for( unsigned long t1=0; t1< Len; t1++ )
			Hash=(Hash<<3)+pThis->String[t1];
		pThis->Flags=(Hash<<16) + 512 + Len;
//
// Add to FastArray
//
		DWORD Index=((Hash&15)<<3)+(Len&7);
		if( FastArray[Index] )
		{
			pThis->pNext=FastArray[Index];
		}
		FastArray[Index]=pThis;
		pThis++;
	}
//
// Add 'Keywords's
//
	for( t0=0; t0<sizeof(Keywords)/sizeof(char*); t0++ )
	{
//
// Get length and hash for string
//
		pThis->pNext=0;
		pThis->String=Keywords[t0];
		pThis->Value=t0;
		DWORD Len=strlen(pThis->String);
		DWORD Hash=0;
		for( unsigned long t1=0; t1< Len; t1++ )
			Hash=(Hash<<3)+pThis->String[t1];
		pThis->Flags=(Hash<<16) + 1024 + Len;
//
// Add to FastArray
//
		DWORD Index=((Hash&15)<<3)+(Len&7);
		if( FastArray[Index] )
		{
			pThis->pNext=FastArray[Index];
		}
		FastArray[Index]=pThis;
		pThis++;
	}
}

//
// Clean up memory used by fast strings
//
void DeleteFastStrings()
{
	if( StringPool )
	{
		gos_Free( StringPool );
		StringPool=0;
	}
}



//
// Find a keyword
//
DWORD FindKeyWord()
{
//
// Get length and hash (If called with same position, only generate hash once)
//
	FindHash=*(BYTE*)pLine;
	BYTE* pTemp=(BYTE*)pLine+1;
	while( KeywordChar[*pTemp] )			// Find length of .variable
	{
		FindHash=(FindHash<<3)+*pTemp;
		pTemp++;
	}
	KeyWordLength=(BYTE)((char*)pTemp-pLine);
	FindIndex=((FindHash&15)<<3)+(KeyWordLength&7);
//
// Search for it
//
	DWORD Flags=(FindHash<<16) + 1024 + KeyWordLength;
//
// Normally it will be first in list
//
	FastString* pThis=FastArray[FindIndex];
	if( !pThis )
		return 0xffffffff;
	
	if( pThis->Flags==Flags && Equals(pLine, pThis->String) )
	{
		pLine+=KeyWordLength;
		if( *pLine==' ' )
			pLine++;
		return pThis->Value;
	}
//
// Otherwise, find it and move it to the top
//
	FastString* pLast=pThis;
	pThis=pThis->pNext;

	while( pThis )
	{
		if( pThis->Flags==Flags && Equals(pLine, pThis->String) )
		{
			pLine+=KeyWordLength;
			if( *pLine==' ' )
				pLine++;

			if( pLast )
			{
				pLast->pNext=pThis->pNext;
				pThis->pNext=FastArray[FindIndex];	// Move to top of list
				FastArray[FindIndex]=pThis;
			}
			return pThis->Value;
		}
		pLast=pThis;
		pThis=pThis->pNext;
	}
//
// Could not find
//
	return 0xffffffff;
}


//
// Find a routine
//
DWORD FindRoutine()
{
//
// Get length and hash (If called with same position, only generate hash once)
//
	FindHash=*(BYTE*)pLine;
	BYTE* pTemp=(BYTE*)pLine+1;
	while( KeywordChar[*pTemp] )			// Find length of .variable
	{
		FindHash=(FindHash<<3)+*pTemp;
		pTemp++;
	}
	KeyWordLength=(BYTE)((char*)pTemp-pLine);
	FindIndex=((FindHash&15)<<3)+(KeyWordLength&7);
//
// Search for it
//
	DWORD Flags=(FindHash<<16) + 512 + KeyWordLength;
//
// Normally it will be first in list
//
	FastString* pThis=FastArray[FindIndex];
	if( !pThis )
		return 0xffffffff;
	
	if( pThis->Flags==Flags && Equals(pLine, pThis->String) )
	{
		pLine+=KeyWordLength;
		if( *pLine==' ' )
			pLine++;
		return pThis->Value;
	}
//
// Otherwise, find it and move it to the top
//
	FastString* pLast=pThis;
	pThis=pThis->pNext;

	while( pThis )
	{
		if( pThis->Flags==Flags && Equals(pLine, pThis->String) )
		{
			pLine+=KeyWordLength;
			if( *pLine==' ' )
				pLine++;

			if( pLast )
			{
				pLast->pNext=pThis->pNext;
				pThis->pNext=FastArray[FindIndex];	// Move to top of list
				FastArray[FindIndex]=pThis;
			}
			return pThis->Value;
		}
		pLast=pThis;
		pThis=pThis->pNext;
	}
//
// Could not find
//
	return 0xffffffff;
}





//
// Find a string or routine
//
// 0=String
// 1=Routine
//
// FindWordResult = result value
//
DWORD FindWord()
{
//
// Get length and hash (If called with same position, only generate hash once)
//
	FindHash=*(BYTE*)pLine;
	BYTE* pTemp=(BYTE*)pLine+1;
	while( KeywordChar[*pTemp] )			// Find length of .variable
	{
		FindHash=(FindHash<<3)+*pTemp;
		pTemp++;
	}
	KeyWordLength=(BYTE)((char*)pTemp-pLine);
	FindIndex=((FindHash&15)<<3)+(KeyWordLength&7);
//
// Search for it
//
	DWORD Flags=(FindHash<<16) + KeyWordLength;
//
// Normally it will be first in list
//
	FastString* pThis=FastArray[FindIndex];
	FastString* pLast=0;

	while( pThis )
	{
		if( (pThis->Flags&0xfffffcff)==Flags && Equals(pLine, pThis->String) )
		{
			pLine+=KeyWordLength;
			if( *pLine==' ' )
				pLine++;

			if( pLast )
			{
				pLast->pNext=pThis->pNext;
				pThis->pNext=FastArray[FindIndex];	// Move to top of list
				FastArray[FindIndex]=pThis;
			}
			FindWordResult=pThis->Value;
			return pThis->Flags&256 ? 0 : 1;
		}
		pLast=pThis;
		pThis=pThis->pNext;
	}
//
// Could not find
//
	return 0xffffffff;
}




//
// See if a string is a "String", "Routine" OR "Keyword"
//
bool CheckStringAgainstReserved(char *pLine)
{
	if(!FirstKeywordChar[*(BYTE*)pLine])
	 	return FALSE;
//
// Get length and hash
//
	DWORD Hash=*pLine;
	BYTE* pTemp=(BYTE*)pLine+1;
	while( KeywordChar[*(BYTE*)pTemp] )			// Find length of .variable
	{
		Hash=(Hash<<3)+*pTemp;
		pTemp++;
	}
	KeyWordLength=(BYTE)((char*)pTemp-pLine);
//
// Search for it
//
	DWORD Flags=(Hash<<16) + KeyWordLength;
	DWORD Index=((Hash&15)<<3)+(KeyWordLength&7);

	FastString* pThis=FastArray[Index];
	while( pThis )
	{
		if( (pThis->Flags&0xfffff8ff)==Flags && Equals(pLine, pThis->String) )
		{
			return TRUE;
		}
		pThis=pThis->pNext;

	}
//
// Could not find
//
	return FALSE;
}


















//
// Delete the current variable
//
void DeleteVariable( VARIABLE* pTemp )
{
//
// Deal with bitmap arrays
//
	if( pTemp->Type==VAR_PANE )
	{
		if( pTemp->ArraySize!=0 )
		{
			for( int i=0; i<pTemp->ArraySize; i++ )
			{
				if( pTemp->pPanes[i] )
					delete pTemp->pPanes[i];
			}
			gos_Free( (void *) pTemp->pPanes );
		}
		else
		{
			if( pTemp->Pane!=0 )
				delete pTemp->Pane;
		}
	}
	else
	if( pTemp->Type==VAR_BITMAP )
	{
		if( pTemp->ArraySize!=0 )
		{
			for( int i=0; i<pTemp->ArraySize; i++ )
			{
				if( pTemp->pSurfaces[i]!=0 )
					gos_DestroySurface(	&pTemp->pSurfaces[i] );
			}
			gos_Free( (void *) pTemp->pSurfaces );
		}
		else
		{
			if( pTemp->Surface!=0 )
				gos_DestroySurface(	&pTemp->Surface );
		}
	}
	else
	if( pTemp->Type==VAR_GAF )
	{
		if( pTemp->ArraySize!=0 )
		{
			for( int i=0; i<pTemp->ArraySize; i++ )
			{
				if( pTemp->pGAFs[i]!=0 )
					gos_DestroyGAFResource(	&pTemp->pGAFs[i] );
			}
			gos_Free( (void *) pTemp->pGAFs );
		}
		else
		{
			if( pTemp->Gaf!=0 )
				gos_DestroyGAFResource(&pTemp->Gaf);
		}
	}
	else
	if( pTemp->Type==VAR_FONT )
	{
		if( pTemp->ArraySize!=0 )
		{
			for( int i=0; i<pTemp->ArraySize; i++ )
			{
				if( pTemp->pSurfaces[i]!=0 )
					gosScript_DestroyFont( (HGOSFONT*)&pTemp->pSurfaces[i] );
			}
			gos_Free( (void *) pTemp->pSurfaces );
		}
		else
		{
			if( pTemp->Surface!=0 )
				gosScript_DestroyFont( (HGOSFONT*)&pTemp->Surface );
		}
	}
	else
	if( pTemp->Type==VAR_FONT3D )
	{
		if( pTemp->ArraySize!=0 )
		{
			for( int i=0; i<pTemp->ArraySize; i++ )
			{
				if( pTemp->pSurfaces[i]!=0 )
					gos_DeleteFont( (HGOSFONT3D)pTemp->pFont3ds[i] );
			}
			gos_Free( (void *) pTemp->pSurfaces );
		}
		else
		{
			if( pTemp->Surface!=0 )
				gos_DeleteFont( (HGOSFONT3D)pTemp->pFont3d );
		}
	}
	else
	if( pTemp->Type==VAR_MOVIE )
	{
		if( pTemp->ArraySize!=0 )
		{
			for( int i=0; i<pTemp->ArraySize; i++ )
			{
				if( pTemp->pSurfaces[i]!=0 )
					gosVideo_DestroyResource( (HGOSVIDEO*)&pTemp->pSurfaces[i] );
			}
			gos_Free( (void *) pTemp->pSurfaces );
		}
		else
		{
			if( pTemp->Surface!=0 )
				gosVideo_DestroyResource( (HGOSVIDEO*)&pTemp->Surface );
		}
	}
	else 
	if( pTemp->Type==VAR_STRING )
	{
		if( pTemp->ArraySize!=0 )
		{
			for( int i=0; i<pTemp->ArraySize; i++ )
			{
				if( pTemp->pValues[i]!=0 )
					gos_Free( (void *)pTemp->pValues[i] );
			}
			gos_Free( (void *) pTemp->pStrings );
		}
		else
		{
			if( pTemp->Value!=0 )
				gos_Free ((void *) pTemp->Value );
		}
	}
	else 
	if( pTemp->Type==VAR_SOUND )
	{
		if( pTemp->ArraySize!=0 )
		{
			for( int i=0; i<pTemp->ArraySize; i++ )
			{
				if( pTemp->pSounds[i]!=0 )
					gosAudio_DestroyResource( (HGOSAUDIO*)&pTemp->pSounds[i] );
			}
			gos_Free( (void *) pTemp->pSounds )	;
		}
		else
		{
			if( pTemp->Sound!=0 )
				gosAudio_DestroyResource( (HGOSAUDIO*)&pTemp->Sound );
		}
	}
	else 
	if( pTemp->Type==VAR_INT )
	{
		if( pTemp->ArraySize!=0 )
		{
			gos_Free( (void *)pTemp->pValues );
		}
	}
	else 
	if( pTemp->Type==VAR_FLOAT )
	{
		if( pTemp->ArraySize!=0 )
		{
			gos_Free( (void *)pTemp->pValues );
		}
	}
	else 
	if( pTemp->Type==VAR_POSITION )
	{
		if( pTemp->ArraySize!=0 )
		{
			for( int i=0; i<pTemp->ArraySize; i++ )
			{
				if( pTemp->pValues[i]!=0 )
					gos_Free((void *)pTemp->pValues[i] );
			}
			gos_Free( (void *) pTemp->pValues );
		}
		else
		{
			if( pTemp->pPosition!=0 )
				gos_Free(pTemp->pPosition);
		}
	}
	else 
	if( pTemp->Type==VAR_CUBE )
	{
		if( pTemp->ArraySize!=0 )
		{
			for( int i=0; i<pTemp->ArraySize; i++ )
			{
				if( pTemp->pValues[i]!=0 )
					gos_Free((void *)pTemp->pCubes[i] );
			}
			gos_Free( (void *) pTemp->pCubes );
		}
		else
		{
			gos_Free((void *)pTemp->pCube);
		}
	}
	else 
	if( pTemp->Type==VAR_OBJECT )
	{
		if( pTemp->ArraySize!=0 && pTemp->pValues)
		{
			for( int i=0; i<pTemp->ArraySize; i++ )
			{
				if( pTemp->pValues[i]!=0 )
				{
					if( pTemp->pValues[i] )
					{
						DeleteScriptObject((OBJECT *)pTemp->pValues[i]);
					}
				}
			}
			gos_Free( (void *) pTemp->pValues );
		}
		else
		{
			if ((OBJECT *)pTemp->pValues != NULL)
			{
				DeleteScriptObject((OBJECT *)pTemp->pValues);
			}
		}
	}
	else 
	if( pTemp->Type==VAR_LIST )
	{
		if( pTemp->ArraySize!=0 )
		{
			for( int i=0; i<pTemp->ArraySize; i++ )
			{
				if( pTemp->pValues[i]!=0 )
					delete ((gosScript_List *)pTemp->pLists[i] );
			}
			gos_Free( (void *) pTemp->pLists );
		}
		else
		{
			delete ((gosScript_List *)pTemp->pList);
		}
	}
//
// Free the actual variable itself
//
	gos_Free( (void *) pTemp ) ;
	pTemp = NULL;
}





//
// Returns the length of a variable and moves past it
//  Assumes the first character already is valid
//
int VariableLength()
{
	pLine++;
	int Length=1;
	while( KeywordChar[*(BYTE*)pLine] )			// Find length of .variable
	{
		pLine++;
		Length++;
	}
#ifdef _DEBUG
	if (*pLine != 0 && *pLine != ' ' &&  *pLine != '[' && *pLine != '=' && gIsDeclaration)
		ScriptError("Bad character in variable name '%c'", *pLine);
#endif
	if( *pLine==' ' )					// Skip any trailing spaces
		pLine++;
	return Length;
}

//
// Returns the length of the keyword that *Source points to
//
int GetKeywordLength( char* Source )
{
	BYTE FirstChar=*(BYTE*)Source;
	if(FirstKeywordChar[FirstChar]==0)
	 	ScriptError("Keyword expected, found '%c'",FirstChar);

	int Length=1;

	while( KeywordChar[*(BYTE*)(Source+Length)]==1 )
		Length++;
	
	if( FirstChar=='@' && *(Source+Length)=='@' )
		Length++;

	return Length;
}



//
// Return a zero terminated string currently pointed to and advance past it.
//
// Use in the pre-precoessor ie: #INLCUDE
//
char* GetSimpleString()
{
	static char FinalBuffer[SCRIPT_MAX_LINE_LENGTH];
	char* Dest=FinalBuffer;

	while(1)
	{
		while(*pLine == ' ') 
			pLine++;

		if (*pLine == ')')
			break;
		if (*pLine == ',' || *pLine == 0)
			break;

		if (*pLine == '"')
		{
			pLine++;
			while( 1 )
			{
				if( Dest>=&FinalBuffer[SCRIPT_MAX_LINE_LENGTH-1] )
					ScriptError("String too long");

				if (*pLine=='"')
				{
					pLine++;
					break;
				}

				if( *pLine==0 )
					ScriptError("Missing quote");

				if( *pLine=='\\' && *(pLine+1)=='\\' )
					*pLine++;				// Skip double \\ to allow old broken syntax

				*Dest++=*pLine++;
			}
			continue;
		}
		else
		{
			ScriptError( "Invalid character in string '%c'", *pLine );
		}
	}

	if( Dest>=&FinalBuffer[SCRIPT_MAX_LINE_LENGTH-1] )
		ScriptError("String too long");

	*Dest++=0;
	return FinalBuffer;
}







//
// Return a zero terminated string currently pointed to and advance past it
//
char* GetString()
{
	static char FinalBuffer[SCRIPT_STRING_LENGTH];
	char Buffer[SCRIPT_STRING_LENGTH];
	char* preserve = pLine;
	char* Dest=Buffer;
	bool weParse = false;

	while(1)
	{
		while(*pLine == ' ') 
			pLine++;

		if (*pLine == ')')
			break;
		if (*pLine == ',' || *pLine == 0)
			break;

		if (*pLine == '"')
		{
			weParse = true;
			pLine++;
			while( 1 )
			{
				if( Dest>=&Buffer[SCRIPT_STRING_LENGTH-1] )
					ScriptError("String too long");

				if (*pLine=='"')
				{
					pLine++;
					break;
				}

				if( *pLine!='"' )
				{
					if( *pLine==0 )
						ScriptError("Missing quote");
					if( *pLine=='\\' )
					{
						pLine++;
						if( *pLine=='"' )			// Look for \" as quote
	 					{
							pLine++;
							*Dest++='"';
							continue;
						}
						else if( *pLine=='n' )
			 			{
							pLine++;				// Look for \n as new line
							*Dest++=0x0d;
							continue;
						}
						else if( *pLine=='t' )
		 				{
							pLine++;				// Look for \t as tab
							*Dest++='\t';
							continue;
						}
						else if( *pLine=='\\' )
		 				{
							pLine++;				// Look for \\ as back slash
							*Dest++='\\';
							continue;
						}
						else
							ScriptError("Unknown escape code");
					}
					else
						*Dest++=*pLine++;
				}
			}
		}
		else
		{
			if( *pLine==' ' )				// Allow multiple strings to become one, eg: "Abc" "def"
				pLine++;
			if( *pLine=='"' )
			{
				pLine++;
				continue;
			}
			else
			if (*pLine==0 || *pLine==',')
			{
				break;
			}
			else
			if (Equals(pLine,"left$"))
			{
				weParse = true;
				pLine += 5;
				if( *pLine==' ' )				
					pLine++;
				if (*pLine != '(')
					ScriptError("left$ is missing '('");
				else 
					pLine++;
				//
				// THIS RECURSION SCREWS UP EVERYTHING!!! --JTR
				//
				char * string = GetString();
				if (*pLine == ' ')
					pLine++;
				if (*pLine != ',')
					ScriptError("left$ is missing a comma");
				else
					pLine++;
				int val = GetExpression();
				if (*pLine == ' ')
					pLine++;
				if (*pLine != ')')
					ScriptError("left$ is missing a ')'");
				else
					pLine++;
				int Temp=_mbstrlen(string);
				if( val > Temp )
					val = Temp;
				for(int i =0; i < val; i++)
				{
					if (LeadByteTable[(unsigned char) *string])
						*Dest++ = *string++;
					*Dest++ =*string++;
				}
				//break;
			}
			else
			if (Equals(pLine,"right$"))
			{
				weParse = true;
				pLine += 6;
				if( *pLine==' ' )				
					pLine++;
				if (*pLine != '(')
					ScriptError("Right$ is missing '('");
				else 
					pLine++;

				//
				// THIS RECURSION SCREWS UP EVERYTHING!!! --JTR
				//
				char * string = GetString();
				if (*pLine == ' ')
					pLine++;
				if (*pLine != ',')
					ScriptError("Right$ is missing a comma");
				else
					pLine++;
				int val = GetExpression();
				if (*pLine == ' ')
					pLine++;
				if (*pLine != ')')
					ScriptError("Right$ is missimg a ')'");
				else
					pLine++;
				int Temp=_mbstrlen(string);
				if( val > Temp )
					val -= Temp;
				for(int i = 0; i < Temp-val; i++)
					string = (char *) _mbsinc((const unsigned char *)string);
				for(i =0; i < val; i++)
				{
					if (LeadByteTable[(unsigned char) *string])
						*Dest++ =*string++;
					*Dest++ =*string++;
				}
				//break;
			}
			else
			if (Equals(pLine,"mid$"))
			{
				weParse = true;
				pLine += 4;
				if( *pLine==' ' )				
					pLine++;
				if (*pLine != '(')
					ScriptError("mid$ is missing '('");
				else 
					pLine++;
				//
				// THIS RECURSION SCREWS UP EVERYTHING!!! --JTR
				//
				char * string = GetString();
				if (*pLine == ' ')
					pLine++;
				if (*pLine != ',')
					ScriptError("mid$ is missing a comma");
				else
					pLine++;
				int left = GetExpression();
				if (*pLine != ',')
					ScriptError("mid$ is missing a comma");
				else
					pLine++;
				int right = GetExpression();
				if (*pLine != ')')
					ScriptError("mid$ is missing a ')'");
				else
					pLine++;
				#ifdef _DEBUG
					int Temp=_mbstrlen(string);		// This is expensive!
					if (left > Temp)
						ScriptError("left bound greater than string length");
					if (right > Temp)
						ScriptError("right bound greater than string length");
					if (left < 0)
						ScriptError("left bound less than 0");
					if (right < 0)
						ScriptError("right bound less than 0");
				#endif

				// DBCS-safe.
				for(int i=0; i < left; i++)
					string = (char *) _mbsinc((const unsigned char *) string);
				for(i=left; i < right; i++)
				{
					if (LeadByteTable[(unsigned char) *string])
						*Dest++ = *string++;
					*Dest++ = *string++;
				}
			}
			else
			if (Equals(pLine,"chr$"))
			{
				weParse = true;
				pLine += 4;
				if( *pLine==' ' )				
					pLine++;
				if (*pLine != '(')
					ScriptError("chr$ is missing '('");
				else 
					pLine++;
				int val = GetExpression();
				if (*pLine != ')')
					ScriptError("chr$ is missing ')'");
				else 
					pLine++;
				if (LeadByteTable[(unsigned char) (val>> 8)])
					*Dest++ = (BYTE)(val >> 8);
				*Dest++ = (BYTE)val;
			}
			else
			if (Equals(pLine,"localize$"))
			{
				weParse = true;
				pLine += 9;
				if (*pLine==' ')
					pLine++;
				if (*pLine!='(')
					ScriptError("Syntax: localize$(<var_int index>)");
				else
					pLine++;
				int val = GetExpression();
				if (*pLine!=')')
					ScriptError("Syntax: localize$(<var_int index>)");
				else
					pLine++;
				if (gosScript_localizationFile == NULL)
				{
					ScriptError("No localization resource has been set");
					return 0;
				}
				char * tmp = gos_GetScriptResourceString(gosScript_localizationFile, val);

				memcpy(Dest, tmp, strlen(tmp));
				Dest += strlen(tmp);
			}
			else
			if (Equals(pLine,"conv$"))
			{
				weParse = true;
				pLine += 5;
				if( *pLine==' ' )				
					pLine++;
				if (*pLine != '(')
					ScriptError("conv$ is missing '('");
				else 
					pLine++;
				int val = GetExpression();
				if (*pLine != ')')
					ScriptError("conv$ is missing ')'");
				else 
					pLine++;
				int Temp=sprintf(Dest, "%d", val);
				Dest+=Temp;
			}
			else
			if (Equals(pLine,"keydesc$"))
			{
				weParse = true;
				pLine += 8;
				if( *pLine==' ' )				
					pLine++;
				if (*pLine != '(')
					ScriptError("keydesc is missing '('");
				else 
					pLine++;
				int val = GetExpression();
				if (*pLine != ')')
					ScriptError("keydesc is missing ')'");
				else 
					pLine++;
				int Temp=sprintf(Dest, "%s", gos_DescribeKey(val));
				Dest+=Temp;
			}
			else
			{
				if( VAR_STRING == GetKeyword() )
				{
					weParse = true;
					if (*pLastVariable)
					{
						int TempLen=strlen((char *) *pLastVariable);
						memcpy(Dest, (char *) *pLastVariable,TempLen );
						Dest += TempLen;
					}
				}
				else
				{
					if (weParse)
						ScriptError("Syntax Error: Cannot parse string. Try using conv$() around non-string components");
					else
					{
						pLine = preserve;
						return NULL;
					}
				}
			}
		}
	}

	if( Dest>=&Buffer[SCRIPT_STRING_LENGTH-1] )
		ScriptError("String too long");

	*Dest++=0;
	if( 0==Buffer[0] && !weParse ) 
	{
		pLine = preserve;
		return NULL;
	}
	else
	{
		memcpy(FinalBuffer, Buffer, Dest-Buffer);
		return FinalBuffer;
	}
}



Cache KeywordCache[MAXCACHE];



//
// This is the main 'getkeyword function'
//
int GetKeyword()
{
//
//
//
	SCRIPT * sourceScript = pScript;
	OBJECT * sourceObject = pObject;
	pLastVariableObject= 0;
	int CurrentChar=(int)*(BYTE*)pLine;
//
// Check for leading spaces
//
	if( CurrentChar==' ' )
	{
		CurrentChar=(int)*(BYTE*)++pLine;
	}
//
// Init variables
//
	DWORD index=(int)pLine&(MAXCACHE-1);
	VARIABLE* pVar;
	int retcode;
	BYTE Length;
	DWORD Type;
	DWORD Hash;
//
// Check for preincrement
//
	if( CurrentChar=='+' && *(pLine+1)=='+' )
	{
		pLine+=2;
		if( *pLine==' ' )
			pLine++;
		return KEY_INC;
	}
//
// Check for predecrement (--variable)
//
	if( CurrentChar=='-' && *(pLine+1)=='-' )
	{
		pLine+=2;
		if( *pLine==' ' )
			pLine++;
		return KEY_DEC;
	}
//
// Reference a variable from another script @ScriptName@variable
//
	if( CurrentChar=='@' )
	{
		SCRIPT* tmp = pListofScripts;

		while(tmp)
		{
			if( ((tmp->Instance == NULL) || (tmp->Instance == pScript->Instance)) && Equals(pLine, tmp->pMainObject->Name) )
			{
				sourceScript = tmp;
				sourceObject = tmp->pMainObject;
				break;
			}
			tmp = tmp->pNext;
		}

		if( !tmp )
			return -1;

		pLine += tmp->pMainObject->NameLength;

		if( *pLine==')' || *pLine==' ' || *pLine==0 || *pLine==',' )
		{
			pLastVariable=(long *)&sourceScript->pMainObject;
			LastVariableScope=SCOPE_GLOBAL;				// Instance of the current script
			return VAR_OBJECT;
		}
	}
//
// Look for Registered Variable  -  $$Variable$$
//
	if( CurrentChar=='$' && *(pLine+1)=='$' )
	{		
		REGVAR* rv = pScriptRegisteredVariables;
		REGVAR* pPrev = NULL;
//
// Find length of variable looking at
//
		char* pTemp=pLine+2;
		while( *pTemp!='$' && *(pTemp+1)!='$' )
		{
			#ifdef _DEBUG
			if( 0==*pTemp )
				ScriptError("Missing $$");
			#endif
			pTemp++;
		}
		int Length=pTemp-pLine+3;

		while(rv)
		{
			if( rv->NameLength==Length && (rv->Instance == NULL || rv->Instance == pScript->Instance) && Equals(pLine, rv->Name) )
			{
//
// Move to top of the list
//
				if( pPrev )
				{
					pPrev->pNext = rv->pNext;
					rv->pNext = pScriptRegisteredVariables;
					pScriptRegisteredVariables = rv;
				}
//
// Array?
//
				pLine+= Length;

				if (*pLine == ' ')
					pLine++;

				if (*pLine != '[')
				{
					if (*pLine == ' ')
						pLine++;
		  			pLastVariable=(long *)rv->Value;
					LastVariableScope=SCOPE_GLOBAL;
					return rv->Type;
				}
				else
				{
					#ifdef _DEBUG
					if (rv->ArraySize == 0)
						ScriptError("Subscript on non-array");
					#endif

					pLine++;
					int val = GetExpression();

					#ifdef _DEBUG
					if (val > rv->ArraySize-1 || val < 0)
					{
						ScriptError("Bad subscript on array");
					}
					#endif

					if (*pLine == ' ')
						pLine++;
					
					#ifdef _DEBUG
					if (*pLine != ']')
						ScriptError("Missing ']' on subscript to array");
					#endif

					if (*++pLine == ' ')
						pLine++;

					if (rv->Type == VAR_INT || rv->Type == VAR_FLOAT)
					{
			  			pLastVariable=(long *)&rv->pValues[val]; 
					}
					else
					{
						char ** spanky = (char **)rv->pValues[0];
			  			pLastVariable=(long *)&spanky[val]; 
					}
					LastVariableScope=SCOPE_GLOBAL;
					return rv->Type;
				}
			}
			pPrev = rv;
			rv = rv->pNext;
		}
		static char tmp[128];
		strncpy(tmp, pLine, Length);
		tmp[Length]=0;

		if (checkingExistence)
			return -1;
		else
			ScriptError( "Variable \"%s\" isn't registered", tmp );
	}
//
// Has to start with a valid character to be a keyboard / variable
//
	if( FirstKeywordChar[CurrentChar]==0 )
		return -1;
//
// Check to see if address is in cache
//
	if( KeywordCache[index].Address==pLine )
	{
		Type=KeywordCache[index].Type;
		Hash=KeywordCache[index].Hash;
		Length=(BYTE)((Hash>>16)&255);
	}
	else
	{
//
// Run through list of reserved keywords looking for a match
//
		Type=FindKeyWord();
		Length=KeyWordLength;
		Hash=(FindHash&65535)+(Length<<16)+((*pLine)<<24);
//
// Update cache, so no hash and look up is necessary next time
//
		KeywordCache[index].Address=pLine;
		KeywordCache[index].Type=Type;
		KeywordCache[index].Hash=Hash;
	}
//
// Found a keyword?
//
	if( Type<1024 )
		return Type;
//
// Look through temp variables (created in message)
//
	if( Type==-2 || Type==0xffffffff )
	{
		pVar=pTempVariables;
		while( pVar )
		{
			if( *(DWORD*)&pVar->Hash==Hash && Length == pVar->NameLength && Equals(pLine+1, pVar->Name+1) )
			{
				if ((retcode = ResolveVariable(pVar)) != -1)
				{
					LastVariableScope=SCOPE_LOCAL;
					KeywordCache[index].Type=(DWORD)-2;
					return retcode;
				}
			}
			pVar=pVar->pNext;
		}
	}
//
// Now run through local to object variables (created in object.init)
//
// Expensive routine!
//
	if( sourceObject && (Type==-3 || Type==0xffffffff) )
	{
		VARIABLE* pLast=0;
		pVar=sourceObject->pVariables;
		while( pVar )
		{
			if( *(DWORD*)&pVar->Hash==Hash && Length == pVar->NameLength && Equals(pLine+1, pVar->Name+1) )
			{
				if ((retcode = ResolveVariable(pVar)) != -1)
				{
					if( pLast )
					{
						if( pLast->pNext==pVar )
						{
							pLast->pNext=pVar->pNext;
							pVar->pNext=sourceObject->pVariables;		// Move this variable to start of list
							sourceObject->pVariables=pVar;
						}
					}
					if( sourceObject==sourceScript->pMainObject )
						LastVariableScope=SCOPE_GLOBAL;
					else
						LastVariableScope=SCOPE_OBJECT;
					KeywordCache[index].Type=(DWORD)-3;
					return retcode;
				}
			}
			pLast=pVar;
			pVar=pVar->pNext;
		}
	}
//
// Look through global variables (created in main)
//
	OBJECT * pObj = sourceScript->pMainObject;
	if( pObj && (Type==-4 || Type==0xffffffff) )
	{
		VARIABLE* pLast=0;
		pVar=pObj->pVariables;
		while( pVar )
		{
			if( *(DWORD*)&pVar->Hash==Hash && Length == pVar->NameLength && Equals(pLine+1, pVar->Name+1) && !gIsDeclaration)
			{
				if( pLast )
				{
					if( pLast->pNext==pVar )
					{
						pLast->pNext=pVar->pNext;
						pVar->pNext=pObj->pVariables;		// Move this variable to start of list
						pObj->pVariables=pVar;
					}
				}
				if ((retcode = ResolveVariable(pVar)) != -1)
				{
					if( pObj==sourceScript->pMainObject )
						LastVariableScope=SCOPE_GLOBAL;
					else
						LastVariableScope=SCOPE_OBJECT;
					KeywordCache[index].Type=(DWORD)-4;
					return retcode;
				}
			}
			pLast=pVar;
			pVar=pVar->pNext;
		}
	}
//
// Now look through all the hard coded keywords
//
	if( Length==8 && Equals( pLine, "instance" ))
	{
		pLine+=8;
		pLastVariable=(long*)&pScript->Instance;
		LastVariableScope=SCOPE_LOCAL;				// Instance of the current script
		return VAR_INT;
	}

	if (Length==6 && Equals(pLine,"sender"))
	{
		pLine+=6;
		if (*pLine != '.')
		{
			pLastVariable=(long *)&g_scriptMailPoster[g_mailStack];
			LastVariableScope=SCOPE_GLOBAL;				// Instance of the current script
			return VAR_OBJECT;
		}
		else
		{
			pLine++;
			char* pTemp=pLine+1;
			while( KeywordChar[*(BYTE*)pTemp] )
			{
				pTemp++;
			}
			BYTE Length=(BYTE)(pTemp-pLine);
			VARIABLE *pVar=g_scriptMailPoster[g_mailStack]->pVariables;
			int retcode = -1;
			while( pVar )
			{
				if( pVar->NameLength==Length && Equals(pLine, pVar->Name) )
				{
					if ((retcode = ResolveVariable(pVar)) != -1)
					{
						if( sourceObject==sourceScript->pMainObject )
							LastVariableScope=SCOPE_GLOBAL;
						else
							LastVariableScope=SCOPE_OBJECT;
						return retcode;
					}
				}
				pVar=pVar->pNext;
			}
		}
	}

	if (Length==6 && Equals(pLine,"parent"))
	{
		pLine+=6;
		if (*pLine != '.')
		{
			if (sourceObject->pParentObject == NULL)
				ScriptError("\"Main\" gui_objects have no parent.");
			pLastVariable=(long *)&sourceObject->pParentObject;
			LastVariableScope=SCOPE_GLOBAL;				// Instance of the current script
			return VAR_OBJECT;
		}
		else
		{
			OBJECT * pFinal = sourceObject->pParentObject;
			#ifdef _DEBUG
			if (pFinal == NULL)
				ScriptError("\"Main\" gui_objects have no parent.");
			#endif

			pLine++;
			char* pTemp=pLine+1;
			while( KeywordChar[*(BYTE*)pTemp] )
			{
				pTemp++;
			}
			int Length=pTemp-pLine;

			while (Length == 6 && Equals(pLine, "parent"))
			{
				pLine+=6;
				if (*pLine != '.')
				{
					#ifdef _DEBUG
					if (pFinal->pParentObject == NULL)
						ScriptError("\"Main\" gui_objects have no parent.");
					#endif
					pLastVariable=(long *)&sourceObject->pParentObject;
					LastVariableScope=SCOPE_GLOBAL;				// Instance of the current script
					return VAR_OBJECT;
				}
				else
				{
					pFinal = pFinal->pParentObject;
					#ifdef _DEBUG
					if (pFinal == NULL)
						ScriptError("\"Main\" gui_objects have no parent.");
					#endif
					pLine++;
					Length=1;
					pTemp=pLine+1;
					while( KeywordChar[*(BYTE*)pTemp] )
					{
						pTemp++;
						Length++;
					}
				}
			}

			VARIABLE *pVar=pFinal->pVariables;
			int retcode = -1;
			while( pVar )
			{
				if( pVar->NameLength==Length && Equals(pLine, pVar->Name) )
				{
					if ((retcode = ResolveVariable(pVar)) != -1)
					{
						if( pFinal==sourceScript->pMainObject )
							LastVariableScope=SCOPE_GLOBAL;
						else
							LastVariableScope=SCOPE_OBJECT;
						return retcode;
					}
				}
				pVar=pVar->pNext;
			}
			static char tmp[128];
			strncpy(tmp, pLine, Length);
			tmp[Length] = 0;
			ScriptError("Cannot resolve variable reference \"%s\"", tmp);
		}
	}

	if (Length==7 && Equals(pLine,"focused"))
	{
		pLine+=7;
		if (*pLine != '.')
		{
			pLastVariable=(long *)&pFocusedObject;
			LastVariableScope=SCOPE_GLOBAL;				// Instance of the current script
			return VAR_OBJECT;
		}
		else
		{
			#ifdef _DEBUG
			if (!pFocusedObject)
				ScriptError("Cannot retrieve object members when nothing is in focus");
			#endif

			VARIABLE *pVar=pFocusedObject->pVariables;
			pLine++;
			Length=1;
			char* pTemp=pLine+1;
			while( KeywordChar[*(BYTE*)pTemp] )
			{
				pTemp++;
				Length++;
			}
			int retcode = -1;
			while( pVar )
			{
				if( pVar->NameLength==Length && Equals(pLine, pVar->Name) )
				{
					if ((retcode = ResolveVariable(pVar)) != -1)
					{
						if( sourceObject==sourceScript->pMainObject )
							LastVariableScope=SCOPE_GLOBAL;
						else
							LastVariableScope=SCOPE_OBJECT;
						return retcode;
					}
				}
				pVar=pVar->pNext;
			}
            // from here by jcem
			if( 7==Length && Equals(pLine, "visible") )
			{
                static int s_Visible = 0;
                s_Visible = pFocusedObject->bActive;
				pLastVariable = (long*)&s_Visible;
				return VAR_INT;
			}
            // to here by jcem
		}
	}

	if( Length==12 && Equals( pLine, "list_getitem")  )
	{
		pLine+=12;
		if (*pLine == ' ')
			pLine++;
		if (*pLine == '(')
			pLine++;
		else
			ScriptError("Syntax Error: list_getitem(<var_list>)");
		int kw = GetKeyword();
		if (kw != VAR_LIST)
			ScriptError("Syntax Error: list_getitem(<var_list>)");
		if (*pLine == ' ')
			pLine++;
		if (*pLine == ')')
			pLine++;
		else
			ScriptError("Syntax Error: list_getitem(<var_list>)");
		if (((gosScript_List *) *pLastVariable)->GetCurrent() == 0)
			ScriptError("Syntax Error: list_getitem(<var_list>) returned NULL");
		int type = (((gosScript_List *) *pLastVariable)->GetCurrentType());
		if (type == VAR_OBJECT)
		{
			if (*pLine == '.')
			{
				pLine++;
				//
				// Find length of variable looking at
				//
				int Length=1;
				char* pTemp=pLine+1;
				while( KeywordChar[*(BYTE*)pTemp] )
				{
					pTemp++;
					Length++;
				}

				VARIABLE * Var = ((gosScript_List *) *pLastVariable)->GetCurrent();
				int Index = ((gosScript_List *) *pLastVariable)->GetCurrentIndex();
				OBJECT * p = NULL;
				if (Index == -1)
				{
					p = (OBJECT *)Var->Value;
				}
				else
				{
					p= (OBJECT *)Var;
				}

				VARIABLE * v = p->pVariables;
			
				retcode=-1;
				
				while( v )
				{
					if( v->NameLength==Length && Equals(pLine, v->Name) )
					{
						if ((retcode = ResolveVariable( v )) != -1)
							return retcode;
					}
					v = v->pNext;
				}
				
				return retcode;
			}
			else
			{
				VARIABLE * Var = ((gosScript_List *) *pLastVariable)->GetCurrent();
				int Index = ((gosScript_List *) *pLastVariable)->GetCurrentIndex();
				if (Index == -1)
				{
					pLastVariable = (long *)&Var->Value;
				}
				else
				{
					pLastVariable = (long *) &((gosScript_List *) *pLastVariable)->cur->pListItemVar;
				}
				return type;
			}
		}
		else
		{
			int Index = ((gosScript_List *) *pLastVariable)->GetCurrentIndex() ;
			if ( Index == -1)
				pLastVariable = (long *) &(((gosScript_List *) *pLastVariable)->GetCurrent()->Value);
			else
				pLastVariable = (long *) &(((gosScript_List *) *pLastVariable)->GetCurrent()->pValues[Index]);
			return 	type;
		}
	}
//
// Check for the mouse
//
	if( Length==5 && Equals( pLine, "mouse" ) )
	{
		pLine+=5;
		if( Equals( pLine, ".x" ) && 0==KeywordChar[pLine[2]] )
		{
			pLine+=2;
			pLastVariable=(long*)&ScriptMousePosition->x;
			LastVariableScope=SCOPE_GLOBAL;
			return VAR_INT;
		}
		if( Equals( pLine, ".lx" ) && 0==KeywordChar[pLine[3]] )
		{
			OBJECT * ptr = sourceObject;
			int offset = -ptr->Cube->p1.x;

			while(ptr)
			{
				offset -= ptr->Coordinates->x;
				if (*ptr->bPosRelative)
					ptr = ptr->pParentObject;
				else
					break;
			}

			ScriptMousePositionLocal->x = ScriptMousePosition->x + offset;

			pLine+=3;
			pLastVariable=(long*)&ScriptMousePositionLocal->x;
			LastVariableScope=SCOPE_GLOBAL;
			return VAR_INT;
		}
		if( Equals( pLine, ".y" ) && 0==KeywordChar[pLine[2]] )
		{
			pLine+=2;
			pLastVariable=(long*)&ScriptMousePosition->y;
			LastVariableScope=SCOPE_GLOBAL;
			return VAR_INT;
		}
		if( Equals( pLine, ".ly" ) && 0==KeywordChar[pLine[3]] )
		{
			OBJECT * ptr = sourceObject;
			int offset = -ptr->Cube->p1.y;

			while(ptr)
			{
				offset -= ptr->Coordinates->y;
				if (*ptr->bPosRelative)
					ptr = ptr->pParentObject;
				else
					break;
			}
			
			ScriptMousePositionLocal->y = ScriptMousePosition->y + offset;
			
			pLine+=3;
			pLastVariable=(long*)&ScriptMousePositionLocal->y;
			LastVariableScope=SCOPE_GLOBAL;
			return VAR_INT;
		}
		if( Equals( pLine, ".z" ) && 0==KeywordChar[pLine[2]] )
		{
			pLine+=2;
			pLastVariable=(long*)&ScriptMousePosition->z;
			LastVariableScope=SCOPE_GLOBAL;
			return VAR_INT;
		}
		if( Equals( pLine, ".position" ) && 0==KeywordChar[pLine[9]] )
		{
			pLine+=9;
			pLastVariable=(long *)&ScriptMousePosition;
			LastVariableScope=SCOPE_GLOBAL;
			return VAR_POSITION;
		}
		if( Equals( pLine, ".left" ) && 0==KeywordChar[pLine[5]] )
		{
			pLine+=5;
			pLastVariable=(long *)&ScriptMouseButton1;
			LastVariableScope=SCOPE_GLOBAL;
			return VAR_INT;
		}
		if( Equals( pLine, ".middle" ) && 0==KeywordChar[pLine[7]] )
		{
			pLine+=7;
			pLastVariable=(long *)&ScriptMouseButton3;
			LastVariableScope=SCOPE_GLOBAL;
			return VAR_INT;
		}
		if( Equals( pLine, ".right" ) && 0==KeywordChar[pLine[6]] )
		{
			pLine+=6;
			pLastVariable=(long *)&ScriptMouseButton2;
			LastVariableScope=SCOPE_GLOBAL;
			return VAR_INT;
		}
		if( Equals( pLine, ".aux1" ) && 0==KeywordChar[pLine[6]] )
		{
			pLine+=6;
			pLastVariable=(long *)&ScriptMouseButton4;
			LastVariableScope=SCOPE_GLOBAL;
			return VAR_INT;
		}
		if( Equals( pLine, ".aux2" ) && 0==KeywordChar[pLine[6]] )
		{
			pLine+=6;
			pLastVariable=(long *)&ScriptMouseButton5;
			LastVariableScope=SCOPE_GLOBAL;
			return VAR_INT;
		}
		ScriptError("You specified the mouse without using .x, .y, .z or .position");
	}
//
// Now check object names looking for object.variable or just object references
//
	int is_this = ( Length==4 && Equals( pLine, "this" ) );				// Check for 'this'
	if (is_this)
	{
		pLine+= 4;
		pLastVariable=(long*)&pObject;
		if (pObj == sourceScript->pMainObject)
			LastVariableScope=SCOPE_GLOBAL;			// Found just an object
		else
			LastVariableScope=SCOPE_LOCAL;			// Found just an object
		return VAR_OBJECT;
	}


	pObj=sourceScript->pListofObjects;
	OBJECT ** useThisAddress = &sourceScript->pListofObjects;
	while( pObj )
	{
		if( (pObj->NameLength==Length && Equals( pLine, pObj->Name )) )
		{
			pLine+=Length;
			if( *pLine==' ' )
				pLine++;
			if( *pLine=='.' )
			{
				pLine++;
				if( *pLine==' ' )						// Skip over . and any spaces
					pLine++;

				#ifdef _DEBUG
				if( FirstKeywordChar[*(BYTE*)pLine]==0 )
					ScriptError("Expecting a object.variable");
				#endif
			
				int Length=1;
				char* pTemp=pLine+1;
				while( KeywordChar[*(BYTE*)pTemp] )			// Find length of .variable
				{
					pTemp++;
					Length++;
				}

				pVar=pObj->pVariables;					// Search through variables in object
				while( pVar )
				{
					if( pVar->NameLength==Length && Equals( pLine, pVar->Name ) )
					{
						pLine+=Length;
						if( *pLine==' ' )
							pLine++;
						if( *pLine=='[' )
						{
							if( *++pLine==' ' )
								pLine++;
							
							int Index=GetNextExpression();
							
							#ifdef _DEBUG
							if( *pLine!=']' )
								ScriptError( "Missing ]" );
							#endif
							
							pLine++;

							#ifdef _DEBUG
							if( 0==pVar->ArraySize )
								ScriptError( "Variable is not an array" );
							if( Index>=pVar->ArraySize )
								ScriptError( "Index too large" );
							#endif

							pLastVariable= (long*)&pVar->pValues[Index];
						}
						else
						{
							if (pVar->Type == VAR_INT || pVar->Type == VAR_FLOAT)
							{
								pLastVariable=(long *) pVar+3;
							}
							else
							{
								pLastVariable=(long *) &pVar->Value;
							}
						}

						if( pObj==sourceScript->pMainObject )
							LastVariableScope=SCOPE_GLOBAL;
						else
							LastVariableScope=SCOPE_OBJECT;
						return pVar->Type;
					}
					pVar=pVar->pNext;
				}
				ScriptError("Could not find variable in object");
			}
			else
			{
				pLastVariable=(long*)useThisAddress;
				if (pObj == sourceScript->pMainObject)
					LastVariableScope=SCOPE_GLOBAL;			// Found just an object
				else
					LastVariableScope=SCOPE_LOCAL;			// Found just an object
				return VAR_OBJECT;
			}
		}
		useThisAddress = &pObj->pNext;
		pObj=pObj->pNext;
	}
//
// Unknown keyword.
//
	pLastVariable=0;				// Default no variable found
	return -1;
}



//






//
// Returns the next number pointed to and advances past it
//
int GetValue()
{
	int Negate=0;
	unsigned int result=0;

	if( *pLine==' ' )
		pLine++;

	while(1)
	{
//
// Decimal number?
//
		if( *pLine<='9' && *pLine>='0' )			// Decimal number
		{
//
// is it a hex number (0x1234?)
//
			if( *pLine=='0' && *(pLine+1)=='x' )	// Start of a HEX number?
			{
				pLine+=2;
				while( (*pLine>='0' && *pLine<='9') || (*pLine>='a' && *pLine<='f') )
				{
					#ifdef _DEBUG
					if( result > 0xffffffff )
						ScriptError("Number overflow");
					#endif
					result = result*16 + (*pLine<='9' ? *pLine-'0' : *pLine-'a'+10);
					pLine++;
				}
				break;
			}
			
			do
			{
				#ifdef _DEBUG
				if( result > 0x19999999 )
					ScriptError("Number overflow");
				#endif
				result = result*10 + *pLine-'0';
				pLine++;
			}
			while( *pLine<='9' && *pLine>='0' );
			
			#ifdef _DEBUG
			if (*pLine == '.')
				ScriptError("Encountered a float constant while evaluating a <var_int>");
			#endif
			break;
		}
		else if( *pLine=='(' )				// Parenthesis
		{
			pLine++;
			result=GetExpression();
			#ifdef _DEBUG
			if( *pLine!=')' )
				ScriptError("Missing parenthesis");
			#endif
			pLine++;
			break;
		}
		else if( *pLine=='!' )				// NOT
		{
			pLine++;
			result=GetValue();
			if( result!=0 )
				result=0;
			else
				result=1;
			break;
		}
		else if( *pLine=='~' )				// Compliment
		{
			pLine++;
			result=~GetExpression();
			break;
		}
		else if( *pLine=='-' && *(pLine+1)=='-' && FirstKeywordChar[*(BYTE*)(pLine+2)] )
		{
			pLine+=2;						// Predecrement
			#ifdef _DEBUG
			char* pKeyWord=pLine;
			#endif

			int Exist=GetKeyword();			// Try and match against variables

			#ifdef _DEBUG
			if( !(Exist==VAR_INT || Exist == VAR_FLOAT) )
			{
				static char Buffer[SCRIPT_MAX_LINE_LENGTH];
				char* pDest=Buffer;

				while( KeywordChar[*(BYTE*)pKeyWord] )
					*pDest++=*pKeyWord++;

				*pDest=0;

				ScriptError("Expected an integer variable, found '%s'",Buffer );	// Found an INT?
			}
			#endif
			
			if (Exist == VAR_INT)
			{
				*pLastVariable+=1;
				result=*pLastVariable;
			}
			else
			{
				*((float*)pLastVariable) += 1.0f;
				result = (int) *((float*)pLastVariable);
			}

			break;
		}
		else if( *pLine=='+' && *(pLine+1)=='+' && FirstKeywordChar[*(BYTE*)(pLine+2)] )
		{
			pLine+=2;						// Preincrement
			#ifdef _DEBUG
			char* pKeyWord=pLine;
			#endif

			int Exist=GetKeyword();			// Try and match against variables

			#ifdef _DEBUG
			if( !(Exist==VAR_INT || Exist == VAR_FLOAT) )
			{
				static char Buffer[SCRIPT_MAX_LINE_LENGTH];
				char* pDest=Buffer;

				while( KeywordChar[*(BYTE*)pKeyWord] )
					*pDest++=*pKeyWord++;

				*pDest=0;

				ScriptError("Expected an integer variable, found '%s'",Buffer );	// Found an INT?
			}
			#endif

			if (Exist == VAR_INT)
			{
				*pLastVariable+=1;
				result=*pLastVariable;
			}
			else
			{
				*((float*)pLastVariable) += 1.0f;
				result = (int) *((float*)pLastVariable);
			}


			break;
		}
		else if( *pLine=='-' )				// Unary minus
		{
			Negate^=1;
			pLine++;
		}
		else if( *pLine=='+' )				// Unary Plus
		{
			Negate=0;
			pLine++;
		}
//
// Is it a floating point number?
//
		#ifdef _DEBUG
		else if (*pLine == '.')
		{
			ScriptError("Encountered a float constant while evaluating a <var_int>");
		}
		#endif
//
// Look for 'functions'
//		
		else if( Equals(pLine,"equal$") )
		{
			static char tmp1[SCRIPT_STRING_LENGTH];
			static char tmp2[SCRIPT_STRING_LENGTH];
			pLine += 6;
			if( *pLine==' ' )				
				pLine++;
			#ifdef _DEBUG
			if (*pLine != '(')
				ScriptError("Syntax Error: equal$(<var_string s1>, <var_string s2>)");
			#endif
			pLine++;
			char * str1 = GetString();
			#ifdef _DEBUG
			if (!str1)
				ScriptError("Syntax Error: equal$(<var_string s1>, <var_string s2>)");
			#endif
				strcpy(tmp1, str1);

			#ifdef _DEBUG
			if (*pLine != ',')
				ScriptError("Syntax Error: equal$(<var_string s1>, <var_string s2>)");
			#endif
			pLine++;
			if (*pLine == ' ')
				pLine++;
			char * str2 = GetString();
			#ifdef _DEBUG
			if (!str2)
				ScriptError("Syntax Error: equal$(<var_string s1>, <var_string s2>)");
			#endif
				strcpy(tmp2, str2);

			#ifdef _DEBUG
			if (*pLine != ')')
				ScriptError("Syntax Error: equal$(<var_string s1>, <var_string s2>)");
			#endif
			pLine++;
			if (strcmpi(tmp1, tmp2) == 0)
				result = 1;
			else
				result = 0;

			break;
		}
		else if( Equals(pLine,"length$"))
		{
			pLine += 7;
			if (*pLine == ' ')
				pLine++;
			#ifdef _DEBUG
			if (*pLine != '(')
				ScriptError("Missing parenthesis");
			#endif
			pLine++;
			#ifdef _DEBUG
			int kw = GetKeyword();
			if (kw != VAR_STRING)
				ScriptError("Length$(<str>) was expecting a string");
			#else
			GetKeyword();
			#endif
			if (*pLine == ' ')
				pLine++;
			#ifdef _DEBUG
			if (*pLine != ')')
				ScriptError("Missing parenthesis");
			#endif
			pLine++;
			if (*pLastVariable == 0) 
				result = 0;
			else 
				result = _mbstrlen((char *) *pLastVariable);
			break;
		}
		else if( (BYTE*)FirstKeywordChar[*(BYTE*)pLine] || (BYTE*)FirstKeywordChar[(*(BYTE*)pLine)-128] )
		{
			char* pKeyWord=pLine;
			int What=-1;
//
// Look for constants (TRUE, FALSE, GameOS enums...)
//
			if( 0==(*((BYTE*)pLine)&128) )
			{
				What=FindWord();

				result=FindWordResult;

				if( What==0 )
					break;									// String found
				if( What==1 )
				{
					DWORD Function=FindWordResult;			// Routine found
					result = ExecuteFunction(Function);
					break;
				}
			}
			else
			{
				*(BYTE*)pLine&=127;
			}
			char* pTemp=pLine;
			int Exist=GetKeyword();
			*(BYTE*)pTemp|=128;

			if( Exist == KEY_RANDOM)
			{
				if (*pLine == ' ')
					pLine++;
				#ifdef _DEBUG
				if (*pLine != '(')
					ScriptError("random was expecting 'random(<low>, <high>)'");
				#endif
				pLine++;
				int lo = GetExpression();
				if (*pLine == ' ')
					pLine++;
				#ifdef _DEBUG
				if (*pLine != ',')
					ScriptError("random was expecting 'random(<low>, <high>)'");
				#endif
				pLine++;
				int hi = GetExpression();
				if (*pLine == ' ')
					pLine++;
				#ifdef _DEBUG
				if (*pLine != ')')
					ScriptError("random was expecting 'random(<low>, <high>)'");
				#endif
				pLine++;
	
#if 1 // by jcem
                if (hi < lo) {
                    hi ^= lo;
                    lo ^= hi;
                    hi ^= lo;
                }
                hi++;
                result = lo + gos_rand() % (hi - lo);
#else
				float percent = ((float) gos_rand())/((float)RAND_MAX);
				result = (unsigned int) ((hi-lo)*percent + lo);
#endif
				break;
			}
	 		if (Exist == VAR_STRING)
			{
				if (*pLastVariable && strlen((char *)*pLastVariable))
					result = *pLastVariable;
				else
					result = 0;
				break;
			}
			if( !(Exist==VAR_INT || Exist == VAR_OBJECT || Exist == VAR_FLOAT) )
			{
				pLine = pKeyWord;
				FUNCTION *pFunc;
				*(BYTE*)pTemp&=127;
				pFunc=GetFunction(pScript, false);
				*(BYTE*)pTemp|=128;

				if (pFunc != NULL)
				{
					return (int)pFunc;
				}

				static char Buffer[SCRIPT_MAX_LINE_LENGTH];
				char* pDest=Buffer;

				while( KeywordChar[(*(BYTE*)pKeyWord)&127] )
					*pDest++=(char)((*pKeyWord++)&127);

				*pDest=0;

				ScriptError("Expected an integer or float variable, found \"%s\"",Buffer );	// Found an INT?
			}

			if (Exist == VAR_FLOAT)
				result=(int)(*((float*)pLastVariable));		// Get value USE float to long - round down!
			else
				result=*pLastVariable;					// Get value

			if( *pLine=='-' && *(pLine+1)=='-' )
			{
				pLine+=2;								// Postdecrement?
				if (Exist == VAR_INT)
				{
					*pLastVariable-=1;
				}
				else
				{
					*((float*)pLastVariable) -= 1.0f;
				}
	
			}
			if( *pLine=='+' && *(pLine+1)=='+' )
			{
				pLine+=2;								// Postincrement?
				if (Exist == VAR_INT)
				{
					*pLastVariable+=1;
				}
				else
				{
					*((float*)pLastVariable) += 1.0f;
				}
			}
			break;
		}
		else
		{
			if (*pLine == '\'')
			{
				pLine++;
				if (*pLine != '\\' && *(pLine+1) == '\'')
				{
					result = *pLine;
					pLine+= 2;
					break;
				}
				else
				{
					pLine++;
					if (*pLine == 'n')
					{
						pLine+= 2;
						result = 0x0d; // return
						break;
					}
					if (*pLine == 't')
					{
						pLine += 2;
						result = 0x09; // tab
						break;
					}
				}

				ScriptError("Couldn't decode 'char'");
			}
			else
				ScriptError("Number expected");
		}
	}
	if( Negate )
		result=0-result;
	return result;
}












//
//
//Precedence	Operator
//
//		80		  () parenthesis
//		75		  ~ (Compliment)
//		70		  ! (not)
//		65		  - (unary minus)
//		60		  + (unary plus)
//		55		  * / %
//		50		  + -
//		45		  << >>
//		40		  < <= > >=
//		35		  = == != <>		(Note both forms of = and <> are allowed)
//		30		  &
//		25		  ^
//		20		  |
//		15		  && AND			(Note both forms of AND are allowed)
//		10		  || OR				(Note both forms of OR are allowed)
//
// Called by GetExpression
//
int DoOperator( int Value1, int Value2, int Operator )
{
	switch( Operator>>8 )
	{
		case 1:
			return Value1-Value2;
		case 2:
			return Value1+Value2;
		case 3:
			#ifdef _DEBUG
			if( Value2==0 )
				ScriptError("Division by zero");
			#endif
			return Value1/Value2;
		case 4:
			return Value1*Value2;
		case 5:
			#ifdef _DEBUG
			if( Value2==0 )
				ScriptError("Division by zero");
			#endif
			return Value1%Value2;
		case 6:
			return Value1<<Value2;
		case 7:
			if( Value1!=Value2 )
				return 1;
			else
				return 0;
		case 8:
			if( Value1<=Value2 )
				return 1;
			else
				return 0;
		case 9:
			if( Value1<Value2 )
				return 1;
			else
				return 0;
		case 0xa:
			return Value1>>Value2;
		case 0xb:
			if( Value1>=Value2 )
				return 1;
			else
				return 0;
		case 0xc:
			if( Value1>Value2 )
				return 1;
			else
				return 0;
		case 0xd:
			if( Value1==Value2 )
				return 1;
			else
				return 0;
		case 0xe:
			return Value1^Value2;
		case 0xf:
			if( Value1 && Value2 )
				return 1;
			else
				return 0;
		case 0x10:
			return Value1&Value2;
		case 0x11:
			if( Value1 || Value2 )
				return 1;
			else
				return 0;
		case 0x12:
			return Value1|Value2;
	}
	ScriptError("Internal Error, bad operator");
	return 0;
}







//
// Called by GetExpression
//
// Low 8 bits   = Precedence
// Hight 8 bits = Operator
//
int GetOperator()
{
	switch( *pLine++ )
	{
		default:
		case 0:
			--pLine;
			return 0;						// End of line or unknown
		case ' ':
			return FloatGetOperator();
		case '-':
			return 0x0150;
		case '+':
			return 0x0250;
		case '/':
			return 0x0355;		
		case '*':
			return 0x0455;		
		case '%':
			return 0x0555;		
		case '<':
			if( *pLine=='<' )		// <<
			{
				pLine++;
				return 0x0645;
			}
			if( *pLine=='>' )		// <>
			{
				pLine++;
				return 0x0735;
			}
			if( *pLine=='=' )		// <=
			{
				pLine++;
				return 0x0840;
			}
			return 0x0940;			// <
		case '>':
			if( *pLine=='>' )		// >>
			{
				pLine++;
				return 0x0a45;
			}
			if( *pLine=='=' )		// >=
			{
				pLine++;
				return 0x0b40;
			}
			return 0x0c40;			// >
		case '=':
			if( *pLine=='=' )		// ==
			{
				pLine++;
				return 0x0d35;
			}
			return 0x0d35;			// =
		case '!':
			if( *pLine=='=' )		// !=
			{
				pLine++;
				return 0x0735;
			}
			break;
		case '^':
			return 0x0e25;
		case '&':
			if( *pLine=='&' )		// &&
			{
				pLine++;
				return 0x0f15;
			}
			return 0x1030;
		case '|':
			if( *pLine=='|' )		// !!
			{
				pLine++;
				return 0x1110;
			}
			return 0x1220;
		case 'a':
			if( *pLine=='n' && *(pLine+1)=='d' && *(pLine+2)==' ')		// AND
			{
				pLine+=3;
				return 0x0f15;
			}
			else pLine--;
			break;
		case 'o':
			if( *pLine=='r' )		// OR
			{
				pLine++;
				return 0x1110;
			}
			else pLine--;
			break;
	}
	return 0;
}




//
// Returns the next function name as an int
//
FUNCTION* GetFunction(SCRIPT * parentScript, bool trapMe)
{
	if( *pLine==' ' )
		pLine++;

	if( FirstKeywordChar[*(BYTE*)pLine]==0 )
	{
		if (GetExpression() == 0)
			return 0;
		else
			ScriptError( "Invalid function name" );
	}
	
	char*pName=pLine;
	int Length=VariableLength();

	if( Length==4 && Equals(pName, "null") )
		return 0;

	FUNCTION* pTemp=parentScript->pFunctions;

	while( pTemp )
	{
		if( pTemp->NameLength==Length && Equals( pName, pTemp->Name ) )
			break;
		pTemp=pTemp->pNext;
	}

	if( !pTemp )
	{
		pLine = pName;

		int kw = GetKeyword();
		if (kw == VAR_INT)
		{
			int val = *pLastVariable;

			SCRIPT *pScript = pListofScripts;

			bool bWeHaveFoundTheCurrentScriptAlready = false;
			while (pScript)
			{
				if (stricmp(pScript->pMainObject->Name, parentScript->pMainObject->Name) == 0)
					bWeHaveFoundTheCurrentScriptAlready = true;

				if (bWeHaveFoundTheCurrentScriptAlready)
				{
					pTemp=pScript->pFunctions;

					while (pTemp)
					{
						if( (int)pTemp == val)
							return pTemp;

						pTemp=pTemp->pNext;
					}

				}
				pScript = pScript->pNext;
			}
		}
		else
		{
			pLine = pName;

			if (*pLine == '@')
			{
				int nScriptNameLen = 0;

				for (nScriptNameLen = 1 ; pLine[nScriptNameLen] != 0 &&  pLine[nScriptNameLen] != '@'; nScriptNameLen++);
				if (pLine[nScriptNameLen] == 0)
					ScriptError( "Expecting a script name surrounded by at (\"@\") symbols." );

				nScriptNameLen++;

				SCRIPT *pScript = pListofScripts;
				FUNCTION *pFunc = NULL;

				//
				// as we run through the list of scripts, we need to know if we've
				// come across the script we're currently in yet, because if not, then
				// the script that has the object we want is going to be unloaded before
				// our script will, which will result in an object pointing to an
				// invalid function
				//
				bool bWeHaveFoundTheCurrentScriptAlready = false;
				while (pScript)
				{
					if (stricmp(pScript->pMainObject->Name, parentScript->pMainObject->Name) == 0)
						bWeHaveFoundTheCurrentScriptAlready = true;

					if (strnicmp(pScript->pMainObject->Name, pLine, nScriptNameLen) == 0)
					{
						if (bWeHaveFoundTheCurrentScriptAlready)
						{
							pLine += nScriptNameLen;
							pFunc = GetFunction(pScript);
							break;
						}
						else
						{
							ScriptError("Referencing an object in a script loaded after the current script is not supported.");
						}
					}

					pScript = pScript->pNext;
				}

				if (pFunc)
				{
					return pFunc;
				}
				else
				{
					if (pScript)
						ScriptError( "The function was not found in the script specified" );
					else
						ScriptError( "The script was not found" );
				}
			}
			else
			if (trapMe)
				ScriptError( "Expecting a function name" );
			else
				return NULL;
		}
	}

	return pTemp;										// Return pointer as an int
}


//
// Returns the next position - returns TRUE if a,b,c format is used, FALSE means a PANE,BITMAP, GAF etc... was found
//
DWORD GetPosition( POSITION* Position, DWORD Explicit )			// Returns next position
{
	if( !Explicit )
	{
		char * tmp = pLine;
		int key = GetKeyword();

		if (key == VAR_PANE)
		{
			Position->x= ((gos_Pane *) *pLastVariable)->GetWidth();
			Position->y= ((gos_Pane *) *pLastVariable)->GetHeight();
			Position->z= 0;
			return 0;
		}
		if (key == VAR_BITMAP)
		{
			Position->x= gos_GetSurfaceWidth(((HGOSSURFACE) *pLastVariable));
			Position->y= gos_GetSurfaceHeight(((HGOSSURFACE) *pLastVariable));
			Position->z= 0;
			return 0;
		}
		if (key == VAR_GAF)
		{
			Position->x= gos_GetSurfaceWidth(gos_GetSurface((HGOSGAF) *pLastVariable));
			Position->y= gos_GetSurfaceHeight(gos_GetSurface((HGOSGAF) *pLastVariable));
			Position->z= 0;
			return 0;
		}
		if (key == VAR_POSITION)
		{
			memcpy( (POSITION *)Position, (char *)*pLastVariable, sizeof(POSITION) );
			return 0;
		}
		pLine = tmp;
	}

	Position->x=GetExpression();

	#ifdef _DEBUG
	if( *pLine!=',' )
		ScriptError( "Position = x,y[,z]" );
	#endif

	pLine++;

	Position->y=GetExpression();

	if (*pLine == ' ')
		pLine++;

	if (*pLine != ',')
	{
		Position->z=0;
	}
	else
	{
		pLine++;
		Position->z=GetExpression();
	}

	return 1;
}

//
// Returns the next position
//
DWORD GetCube( CUBE* cube, DWORD Explicit )			// Returns next position
{
	POSITION pos1, pos2;
	if( !Explicit )
	{
		char * save = pLine;
		int key = GetKeyword();
		if (key == VAR_PANE)
		{
			#ifdef _DEBUG
			if (!*pLastVariable)
			{
				ScriptError("Your attempting to access an uninitialized pane"); 
			}
			#endif
			cube->p1.x = cube->p1.y = cube->p1.z = 0;
			cube->p2.x = ( (gos_Pane *) *pLastVariable)->GetWidth();
			cube->p2.y = ( (gos_Pane *) *pLastVariable)->GetHeight();
			cube->p2.z = 0;
			return 0;
		}
		else
		if (key == VAR_BITMAP)
		{
			#ifdef _DEBUG
			if (!*pLastVariable)
			{
				ScriptError("Your attempting to access an uninitialized bitmap"); 
			}
			#endif
			cube->p1.x = cube->p1.y = cube->p1.z = 0;
			cube->p2.x = gos_GetSurfaceWidth( (HGOSSURFACE) *pLastVariable);
			cube->p2.y = gos_GetSurfaceHeight( (HGOSSURFACE) *pLastVariable);
			cube->p2.z = 0;
			return 0;
		}
		else
		if (key == VAR_GAF)
		{
			#ifdef _DEBUG
			if (!*pLastVariable)
			{
				ScriptError("Your attempting to access an uninitialized gaf"); 
			}
			#endif
			cube->p1.x = cube->p1.y = cube->p1.z = 0;
			cube->p2.x = gos_GetSurfaceWidth( gos_GetSurface((HGOSGAF) *pLastVariable ));
			cube->p2.y = gos_GetSurfaceHeight( gos_GetSurface((HGOSGAF) *pLastVariable ));
			cube->p2.z = 0;
			return 0;
		}
		else
		if (key == VAR_CUBE)
		{
			#ifdef _DEBUG
			if (!*pLastVariable)
			{
				ScriptError("Your attempting to access an uninitialized cube"); 
			}
			#endif
			memcpy(cube,(void *)*pLastVariable,sizeof(CUBE));
			return 0;
		}
		else
		if (key == VAR_POSITION)
		{
			#ifdef _DEBUG
			if (!*pLastVariable)
			{
				ScriptError("Your attempting to access an uninitialized position"); 
			}
			#endif
			memcpy(&pos1,(void *) *pLastVariable,sizeof(POSITION));
			#ifdef _DEBUG
			if( *pLine!='t' && *(pLine+1)!='o' )
			{
				ScriptError("Syntax error: looking for keyword 'to'" );
			}
			#endif
			pLine+=2;
			if( *pLine==' ' )
				pLine++;

			GetPosition(&pos2);

			memcpy(&cube->p1,&pos1,sizeof(POSITION));
			memcpy(&cube->p2,&pos2,sizeof(POSITION));
			return 0;
		}
		pLine = save;
	}

	DWORD posa=GetPosition(&pos1, Explicit&2 );

	#ifdef _DEBUG
	if( *pLine!='t' && *(pLine+1)!='o' )
	{
		ScriptError("Syntax error: looking for keyword 'to'" );
	}
	#endif

	pLine+=2;
	if( *pLine==' ' )
		pLine++;

	DWORD posb=GetPosition(&pos2, Explicit&4 );

	memcpy(&cube->p1,&pos1,sizeof(POSITION));
	memcpy(&cube->p2,&pos2,sizeof(POSITION));
		
	return 1 + (posa ? 2 : 0) + (posb ? 4 : 0);
}








//
// Return next value - but no pointer to variable
//
int GetNextExpression()
{
	long* tv=pLastVariable;
	VAR_SCOPE tlv=LastVariableScope;
	int result=GetExpression();
	pLastVariable=tv;
	LastVariableScope=tlv;
	return result;
}




//
// Get next value
//
int GetExpression()
{
	int Stack[32][2];					// 0=Value, 1=Precedence, Operator
	int result=0, NextOp, sp=0;

	while(1)
	{
		result = GetValue();			// Get next value and operator
		NextOp = GetOperator();
		if( *pLine==' ' )				// Skip any spaces
			pLine++;

		while( (sp!=0) && (NextOp&0xff) <= (Stack[sp-1][1]&0xff) )			// Changed to <= to fix 100-60-20 bug
		{
			result=DoOperator( Stack[sp-1][0], result, Stack[sp-1][1] );
			sp--;
		}								// Pop and execute lower priority operators

		if( NextOp==0 )					// Reached end of expression?
			break;
	
		#ifdef _DEBUG
		if( sp==32 )
			ScriptError("Expression too complex");
		#endif

		Stack[sp][0]=result;			// Else, save value and operator
		Stack[sp++][1]=NextOp;
	}

	return result;
}

int ExecuteFunction(int Function)
{
	int result = -1;
	switch( Function )
	{
		case ROUTINE_DBLCLICK:
		{
			if (*pLine == ' ')
				pLine++;
			if (*pLine != '(')
				ScriptError("Syntax Error: dblclick(var_object, [var_int on/off])");
			else
				pLine++;
			if (*pLine == ' ')
				pLine++;

			int kw = GetKeyword();

			if (!(kw == VAR_OBJECT || kw == VAR_INT))
				ScriptError("Syntax Error: dblclick(var_object [, var_int on/off])");

			if (*pLine == ' ')
				pLine++;
			
			if (*pLine != ')')
			{
				if (*pLine != ',')
					ScriptError("Syntax Error: dblclick(var_object [, var_int on/off])");
				else
				{
					pLine++;
					OBJECT * theObj = (OBJECT *) *pLastVariable;
					int val = GetExpression();
					if (val != 0 && !Environment.allowDoubleClicks)
						ScriptError("GameOS Environment flag 'allowDoubleClicks' is false");
					((OBJECT *)(theObj))->dwDblClicks = val ? 1 : 0;

					if (*pLine == ' ')
						pLine++;
					if (*pLine != ')')
						ScriptError("Syntax Error: dblclick(var_object [, var_int on/off])");
					else
						pLine++;
					return val;
				}
			}
			else
			{
				pLine++;
				return ((OBJECT *)(*pLastVariable))->dwDblClicks;
			}

			int chan = GetExpression();
			if (*pLine == ' ')
				pLine++;
			if (*pLine != ')')
				ScriptError("Syntax Error: GetVolume([var_int on/off)");
			else
				pLine++;
			float val;
			gosAudio_GetChannelSlider(chan, gosAudio_Volume, &val);
			return (unsigned int) (val * 100);
		}
		case ROUTINE_SETPOINTER:
		{
			if (*pLine == ' ')
				pLine++;
			if (*pLine != '(')
				ScriptError("Syntax: setpointer(<var_int index>) where -1 = mouse, # = joystick");
			else
				pLine++;
			int val = GetExpression();
			if ( *pLine == ' ' )
				pLine++;
			if ( *pLine != ')' || (val < 0 && val != -1) )
				ScriptError("Syntax: setpointer(<var_int index>) where -1 = mouse, # = joystick");
			else
				pLine++;
			if (val == -1)
			{
				// use the mouse
				ScriptPointerDevice = val;
				return 1;
			}
			else
			{
				if (val-1 > (int) gosJoystick_CountJoysticks( 0 ))
					ScriptError("There is no joystick #%d", val);
				else
				{
					gosJoystick_SetPolling(val, true);
					ScriptPointerDevice = val;
					return 1;
				}
			}
		}
		case ROUTINE_LAUNCH:
		{
			char appName[256];
			char arg[12][256];
			for(int i=0; i < 12; i++)
				arg[i][0] = 0;
			i=0;

			if (*pLine == ' ')
				pLine++;
			if (*pLine != '(')
				ScriptError("Missing paranthesis");
			pLine++;

			char * str = GetString();
			#ifdef _DEBUG
			if (!str)
				ScriptError("Syntax error: launch(<var_string appName>)");
			#endif
			strcpy(appName, str);
			if (*pLine == ' ')
				pLine++;
			if (*pLine != ')')
				ScriptError("Missing end paranthesis");
			pLine++;

			SPEW(( GROUP_SCRIPTS, "launching %s", appName ));
			return gos_EnableSetting(gos_Set_TriggerBrowser, (unsigned long) appName);
		}
		case ROUTINE_QUERYCHAR:
		{
			if (*pLine == ' ')
				pLine++;
			if (*pLine != '(')
				ScriptError("Syntax: querychar(<var_string str>, <var_int>)");
			else
				pLine++;
			int kw = GetKeyword();
			unsigned char * str = NULL;
			if (kw != VAR_STRING)
			{
				str = (unsigned char *) GetString();
				if (!str)
					ScriptError("Syntax: querychar(<var_string str>, <var_int>)");
			}
			else
			{
				str = (unsigned char *) *pLastVariable;
			}
			
			if (*pLine != ',')
				ScriptError("Syntax: querychar(<var_string str>, <var_int>)");
			else
				pLine++;
			int index = GetExpression();

			if ( index >= (int) _mbstrlen((char *)str) )
			{
				ScriptError("Called querychar beyond end of string");
				return 0;
			}
			if (index < 0 )
			{
				ScriptError("Called querychar before beginning of string");
				return 0;
			}

			str = _mbsninc((unsigned char *) str, index);
			result = (unsigned int) _mbsnextc(str);

			if (*pLine != ')')
				ScriptError("Syntax: querychar(<var_string str>, <var_int>)");
			return result;
		}

		case ROUTINE_MAIL:
		{
			if (*pLine == ' ')
				pLine++;
			if (*pLine != '(')
				ScriptError("Syntax: mail(<var_int>[,<var_int>,...] [, <var_object>])");
			else
				pLine++;
			if (g_mailStack >= MAX_MAILSTACK)
				ScriptError("Mail is nesting too deeply");
			while (*pLine == ' ')
				pLine++;

			g_scriptMailPoster[g_mailStack+1] = pObject;

			int count = 0;
			while(*pLine != ')')
			{
				g_scriptPostedInteger[g_mailStack+1][count] = GetExpression();
				while (*pLine == ' ')
					pLine++;
				count++;
				if (*pLine == ',')
					pLine++;
				else
					break;
				if (count == 8)
					ScriptError("Mail can only take up to 7 arguments");
			}
			g_mailStack++;

			OBJECT * dst = NULL;

			if (count > 1)
				 dst = (OBJECT *) g_scriptPostedInteger[g_mailStack][count-1];
			else
			{
				dst = pObject->pParentObject;
				if (dst == 0)
					ScriptError("Syntax: %s cannot mail to parent. It doesn't have one",(OBJECT *) pObject->Name);
			}

			result = SendScriptMessage( dst, MSG_GUI_MAILBOX );		
			result = g_scriptPostedInteger[g_mailStack][0];
			g_mailStack--;
			gosASSERT(g_mailStack >= 0);
			return result;
		}
		case ROUTINE_JSPOLL:
		{
			if (*pLine == ' ')
				pLine++;
			if (*pLine != '(')
				ScriptError("Syntax error: js_setpolling(<var_int joystick>, <var_int flag>)");
			else
				pLine++;
			int js = GetExpression();
	
			if (*pLine == ' ')
				pLine++;
			if (*pLine != ',')
				ScriptError("Syntax error: js_setpolling(<var_int joystick>, <var_int flag>)");
			else 
				pLine++;
			int flag = GetExpression();
			bool bflag = 0;
			if (flag != 0 && flag != 1)
				ScriptError("Syntax error: 2nd parameter must be true/false or 1/0");
			if (flag)
				bflag = 1;
			if (*pLine != ')')
				ScriptError("Syntax error: js_setpolling(<var_int joystick>, <var_int flag>)");

			if (js < 0 || gosJoystick_CountJoysticks( 0 ) <= (unsigned int)js)
				ScriptError("There is no joystick device #%d", js);
			else
				gosJoystick_SetPolling(js, bflag);
	
			return 0;
		}
		case ROUTINE_COUNTJS:
		{
			if (*pLine == ' ')
				pLine++;
			if (*pLine != '(')
				ScriptError("Syntax error: js_countdevices( <var_list> ) - missing parenthesis");
			else
				pLine++;

			if (*pLine != ')')
				ScriptError("Syntax error: js_countdevices( <var_list> ) - missing parenthesis");
			else
				*pLine++;

			return gosJoystick_CountJoysticks( 0 );
		}
		case ROUTINE_JSGETAXIS:
		{
			if (*pLine == ' ')
				pLine++;
			if (*pLine != '(')
				ScriptError("Syntax error: js_getaxis(<var_int joystick#>, <var_int axis>)");
			else
				pLine++;
			int js = GetExpression();
			if (*pLine != ',')
				ScriptError("Syntax error: js_getaxis(<var_int joystick#>, <var_int axis>)");
			else 
				pLine++;
			int axis = GetExpression();

			if (*pLine != ')')
				ScriptError("Syntax error: js_getaxis(<var_int joystick#>, <var_int axis>)");
			else
				pLine++;
	
			return (int) (1000*gosJoystick_GetAxis(js,(GOSJoystickAxis)axis));
		}
		case ROUTINE_JSGETBUTTON:
		{
			if (*pLine == ' ')
				pLine++;
			if (*pLine != '(')
				ScriptError("Syntax error: js_getbutton(<var_int joystick#>, <var_int button#>)");
			else
				pLine++;
			int js = GetExpression();
			if (*pLine != ',')
				ScriptError("Syntax error: js_getbutton(<var_int joystick#>, <var_int button#>)");
			else 
				pLine++;
			int button = GetExpression();

			if (*pLine != ')')
				ScriptError("Syntax error: js_getbutton(<var_int joystick#>, <var_int button#>)");
			else
				pLine++;
	
			return gosJoystick_ButtonStatus(js, button);
		}
		case ROUTINE_COUNTBUTTONS:
		{
			if (*pLine == ' ')
				pLine++;
			if (*pLine != '(')
				ScriptError("Syntax error: js_countbuttons(<var_int joystick>)");
			else
				pLine++;
			int js = GetExpression();
	
			if (*pLine != ')')
				ScriptError("Syntax error: js_countbuttons( <var_list> )");
			else
				*pLine++;
	
			gosJoystick_Info ji;
			memset(&ji,0,sizeof(ji));
			gosJoystick_GetInfo(js, &ji);
			return ji.nButtons;
		}
		case ROUTINE_ISAXISVALID:
		{
   			if (*pLine == ' ')
				pLine++;
			if (*pLine != '(')
				ScriptError("Syntax error: js_isaxisvalid(<var_int joystick#>, <var_int axis>)");
			else
				pLine++;
			int js = GetExpression();
			if (*pLine != ',')
				ScriptError("Syntax error: js_isaxisvalid(<var_int joystick#>, <var_int axis>)");
			else 
				pLine++;
			int axis = GetExpression();

			if (*pLine != ')')
				ScriptError("Syntax error: js_isaxisvalid(<var_int joystick#>, <var_int axis>)");
			else
				pLine++;
	
			gosJoystick_Info ji;
			memset(&ji,0,sizeof(ji));
			gosJoystick_GetInfo(js, &ji);
			return (ji.bAxisValid & (1<<axis)) ? 1 : 0;
		}

		case ROUTINE_TOP:
		{
			if (*pLine == ' ')
				pLine++;
			if (*pLine != '(')
				ScriptError("Syntax error: list_top( <var_list> )");
			else
				pLine++;
			int Exists = GetKeyword();

			if (Exists != VAR_LIST)
				ScriptError("Syntax error: list_top( <var_list> )");

			while(*pLine != ')' && *pLine != 0)
				*pLine++;

			if (*pLine == 0)
				ScriptError("Syntax error: list_top( <var_list> )");
			else
				*pLine++;

			((gosScript_List*) *pLastVariable)->Top();
			return 0;
		}
		case ROUTINE_BOTTOM:
		{
			if (*pLine == ' ')
				pLine++;
			if (*pLine != '(')
				ScriptError("Syntax error: list_bottom( <var_list> )");
			else
				pLine++;
			int Exists = GetKeyword();

			if (Exists != VAR_LIST)
				ScriptError("Syntax error: list_bottom( <var_list> )");

			while(*pLine != ')' && *pLine != 0)
				*pLine++;

			if (*pLine == 0)
				ScriptError("Syntax error: list_bottom( <var_list> )");
			else
				*pLine++;

			((gosScript_List*) *pLastVariable)->Bottom();
			return 0;
		}
		case ROUTINE_NEXT:
		{
			if (*pLine == ' ')
				pLine++;
			if (*pLine != '(')
				ScriptError("Syntax error: list_next( <var_list> )");
			else
				pLine++;
			int Exists = GetKeyword();

			if (Exists != VAR_LIST)
				ScriptError("Syntax error: list_next( <var_list> )");

			while(*pLine != ')' && *pLine != 0)
				*pLine++;

			if (*pLine == 0)
				ScriptError("Syntax error: list_next( <var_list> )");
			else
				*pLine++;

			return ((gosScript_List*) *pLastVariable)->Next();
		}
		case ROUTINE_PREV:
		{
			if (*pLine == ' ')
				pLine++;
			if (*pLine != '(')
				ScriptError("Syntax error: list_prev( <var_list> )");
			else
				pLine++;
			int Exists = GetKeyword();

			if (Exists != VAR_LIST)
				ScriptError("Syntax error: list_prev( <var_list> )");

			while(*pLine != ')' && *pLine != 0)
				*pLine++;

			if (*pLine == 0)
				ScriptError("Syntax error: list_prev( <var_list> )");
			else
				*pLine++;

			return ((gosScript_List*) *pLastVariable)->Prev();
		}
		case ROUTINE_ADD:
		{
			VARIABLE * toAdd = 0;
			if (*pLine == ' ')
				pLine++;
			if (*pLine != '(')
				ScriptError("Syntax error: list_add( <var>, <var_list> )");
			else
				pLine++;
			int Exists = GetKeyword();
			if (Exists == -1)
				ScriptError("Syntax error: list_add( <var>, <var_list> )");
			else
				toAdd = pLastVariableObject;
			int index = pLastVariableObjectIndex;
			int type = Exists;

			if (*pLine == ' ')
				pLine++;
			if (*pLine == ',')
				pLine++;
			else
				ScriptError("Syntax error: list_add( <var>, <var_list> )");

			Exists = GetKeyword();

			if (Exists != VAR_LIST)
				ScriptError("Syntax error: list_add( <var>, <var_list> )");

			while(*pLine != ')' && *pLine != 0)
				*pLine++;

			if (*pLine == 0)
				ScriptError("Syntax error: list_add( var>, <var_list> )");
			else
				*pLine++;

			((gosScript_List*) *pLastVariable)->Add(toAdd, type, index);

			return 0;
		}
		case ROUTINE_REMOVE:
		{
			VARIABLE * toDel = 0;
			if (*pLine == ' ')
				pLine++;
			if (*pLine != '(')
				ScriptError("Syntax error: list_del( <var>, <var_list> )");
			else
				pLine++;
			int Exists = GetKeyword();
			if (Exists == -1)
				ScriptError("Syntax error: list_del( <var>, <var_list> )");
			else
				toDel = pLastVariableObject;
			int index = pLastVariableObjectIndex;
			int type = Exists;


			if (*pLine == ' ')
				pLine++;
			if (*pLine == ',')
				pLine++;
			else
				ScriptError("Syntax error: list_del( <var>, <var_list> )");

			Exists = GetKeyword();

			if (Exists != VAR_LIST)
				ScriptError("Syntax error: list_del( <var>, <var_list> )");

			while(*pLine != ')' && *pLine != 0)
				*pLine++;

			if (*pLine == 0)
				ScriptError("Syntax error: list_del( <var>, <var_list> )");
			else
				*pLine++;

			return ((gosScript_List*) *pLastVariable)->Del(toDel, type, index);
		}
		case ROUTINE_LENGTH:
		{
			if (*pLine == ' ')
				pLine++;
			if (*pLine != '(')
				ScriptError("Syntax error: list_length( <var_list> )");
			else
				pLine++;
			int Exists = GetKeyword();

			if (Exists != VAR_LIST)
				ScriptError("Syntax error: list_length( <var_list> )");

			while(*pLine != ')' && *pLine != 0)
				*pLine++;

			if (*pLine == 0)
				ScriptError("Syntax error: list_length( <var_list> )");
			else
				*pLine++;

			return ((gosScript_List*) *pLastVariable)->Length();
		}
		case ROUTINE_EMPTY:
		{
			if (*pLine == ' ')
				pLine++;
			if (*pLine != '(')
				ScriptError("Syntax error: list_empty( <var_list> )");
			else
				pLine++;
			int Exists = GetKeyword();

			if (Exists != VAR_LIST)
				ScriptError("Syntax error: list_empty( <var_list> )");

			while(*pLine != ')' && *pLine != 0)
				*pLine++;

			if (*pLine == 0)
				ScriptError("Syntax error: list_empty( <var_list> )");
			else
				*pLine++;

			return ((gosScript_List*) *pLastVariable)->Empty();
		}
		case ROUTINE_PACKCOLOR:
		{
			if (*pLine == ' ')
				pLine++;
			if (*pLine != '(')
				ScriptError("Syntax error: packcolor(r,g,b,a)");
			else 
				pLine++;
			POSITION p;
			GetPosition(&p);
			if (*pLine == ' ')
				pLine++;
			if (*pLine != ',')
				ScriptError("Syntax error: packcolor(r,g,b,a)");
			else
				pLine++;
			int val = GetExpression();

			int thecolor = (val << 24) + (p.x << 16) + (p.y<<8) + p.z; 

			if (*pLine != ')')
				ScriptError("Syntax error: packcolor(r,g,b,a)");
			else
				pLine++;						
			return thecolor;
		}
		case ROUTINE_GETRESX:
		{
			if( *pLine==' ' )
				pLine++;
			#ifdef _DEBUG
			if( *pLine!='(' && *(pLine+1)!=')' )
				ScriptError("Syntax error: getresx()");
			#endif
			pLine+=2;
			if( *pLine=='/' && *(pLine+1)=='2' )
			{
				pLine+=2;
				return (unsigned int) Environment.screenWidth>>1;
			}
			return (unsigned int) Environment.screenWidth;
		}
		case ROUTINE_GETRESY:
		{
			if( *pLine == ' ' )
				pLine++;
			#ifdef _DEBUG
			if( *pLine!='(' && *(pLine+1)!=')' )
				ScriptError("Syntax error: getresy()");
			#endif
			pLine+=2;
			return (unsigned int) Environment.screenHeight;
		}
		case ROUTINE_EXISTS:
		{
			checkingExistence = true;
			if (*pLine == ' ')
				pLine++;
			if (*pLine != '(')
				ScriptError("Syntax error: exists( <variable name>[, var_type] )");
			else
				pLine++;
			int Exists = GetKeyword();

			if (*pLine == ' ')
				pLine++;
			if (*pLine == ',')
			{
				pLine++;
				if (*pLine == ' ')
					pLine++;
				long * tmp = pLastVariable;
				int kw2 = GetKeyword();
				checkingExistence = false;
				if (!(kw2 == KEY_INT || kw2 == KEY_FLOAT || kw2 == KEY_PANE || kw2 == KEY_SOUND || kw2 == KEY_STRING || 
					kw2 == VAR_POSITION || kw2 == VAR_CUBE || kw2 == KEY_BITMAP || kw2 == KEY_OBJECT || kw2 == KEY_FONT || kw2 == KEY_FONT3D ||
					kw2 == KEY_GAF || kw2 == KEY_LIST))
					ScriptError("Syntax error: exists( <variable name>[, var_type] )");
				if (kw2 != VAR_OBJECT)
				{
					while(*pLine != ')' && *pLine != 0)
						*pLine++;

					if (*pLine == 0)
						ScriptError("Syntax error: exists( <variable name>[, var_type] )");
					else
						*pLine++;

					pLastVariable = tmp;
					if (Exists == -1)
						return false;
					else
						return true;
				}
				else
					pLastVariable = tmp;
			}
			if (Exists == VAR_OBJECT)
			{
				if (  ((OBJECT *)(*pLastVariable))->pFunction == 0)
					Exists = -1;
			}
			else
				if (Exists != -1 && *pLastVariable == 0)
					Exists = -1;

			while(*pLine != ')' && *pLine != 0)
				*pLine++;

			if (*pLine == 0)
				ScriptError("Syntax error: exists( <variable name>[, var_type] )");
			else
				*pLine++;

			if (Exists != -1)
				return 1;
			else
				return 0;
		}
		case ROUTINE_GOTFOCUS:
		{
			int Exist;
			if (*pLine == ' ')
				pLine++;
			if (*pLine != '(')
				goto gotfocus_err;
			else 
				pLine++;

			Exist = GetKeyword();
			if (Exist != VAR_OBJECT)
				goto gotfocus_err;
			if (*pLine != ')')
				goto gotfocus_err;
			else
				pLine++;						
			return (pFocusedObject == (OBJECT *) *pLastVariable);
gotfocus_err:
			ScriptError("Syntax error: gotfocus( <var_object> )");

		}
		case ROUTINE_GETPRINT3DPOSX:
		{
			if (*pLine == ' ')
				pLine++;
			if (*pLine != '(')
				ScriptError("Syntax error: getprint3dposx()");
			else 
				pLine++;
			if (*pLine != ')')
				ScriptError("Syntax error: getprint3dposx()");
			else
				pLine++;						
			int FontX,FontY;
			gos_TextGetPrintPosition( &FontX, &FontY );
			return (unsigned int) FontX;
		}
		case ROUTINE_GETPRINT3DPOSY:
		{
			if (*pLine == ' ')
				pLine++;
			if (*pLine != '(')
				ScriptError("Syntax error: getprint3dposy()");
			else 
				pLine++;
			if (*pLine != ')')
				ScriptError("Syntax error: getprint3dposy()");
			else
				pLine++;						
			int FontX,FontY;
			gos_TextGetPrintPosition( &FontX, &FontY );
			return (unsigned int) FontY;
		}
		case ROUTINE_GETPRINT3DHEIGHT:
		{
			if (*pLine == ' ')
				pLine++;
			#ifdef _DEBUG
			if (*pLine != '(')
				ScriptError("Syntax error: getprint3dheight(<var_string>)");
			#endif
			pLine++;
			char* tmp;
			tmp = GetString();
			#ifdef _DEBUG
			if (*pLine != ')')
				ScriptError("Syntax error: getprint3dheight(<var_string>)");
			#endif
			pLine++;						
			DWORD h,w;
			gos_TextStringLength( &w, &h, "%s",tmp);
			return (unsigned int) h;
		}
		case ROUTINE_GETPRINT3DWIDTH:
		{
			if (*pLine == ' ')
				pLine++;
			#ifdef _DEBUG
			if (*pLine != '(')
				ScriptError("Syntax error: getprint3dwidth(<var_string>)");
			#endif
			pLine++;
			char * tmp;
			tmp = GetString();
			#ifdef _DEBUG
			if (*pLine != ')')
				ScriptError("Syntax error: getprint3dwidth(<var_string>)");
			#endif
			pLine++;						
			DWORD h,w;
			gos_TextStringLength( &w, &h, "%s",tmp);
			return (unsigned int) w;
		}
		case ROUTINE_GETTIME: // 1/60 & !real-time(could be paused by logic or modal-script)
		case ROUTINE_GETTIMEX: // 1/1000 & real-time
		{
			if (*pLine == ' ')
				pLine++;
			if (*pLine != '(')
				ScriptError("Syntax error: gettime()");
			else 
				pLine++;
			if (*pLine == ' ')
				pLine++;
			if (*pLine != ')')
				ScriptError("Syntax error: gettime()");
			else
				pLine++;
			if (Function == ROUTINE_GETTIMEX)
				return (unsigned int) (gos_GetHiResTime() * 1000.0f); // gos_GetElapsedTime(true)
			return (unsigned int) (gos_GetElapsedTime() * 60.0f);
		}
		case ROUTINE_GETMESSAGE:
		{
			if (*pLine == ' ')
				pLine++;
			if (*pLine != '(')
				ScriptError("Syntax error: getmessage([var_int index])");
			else 
				pLine++;
			while (*pLine == ' ')
				pLine++;
			if (*pLine != ')')
			{
				int whichItem = GetExpression();
				while (*pLine == ' ')
					pLine++;
				if (*pLine != ')')
					ScriptError("Syntax error: getmessage([var_int index])");
				else
				{
					pLine++;
					return g_scriptPostedInteger[g_mailStack][whichItem];
				}
			}
			else
				pLine++;
			return g_scriptPostedInteger[g_mailStack][0];
		}
		case ROUTINE_CALLBACK:
		{
			#ifdef LAB_ONLY
			__int64 StartTime=GetCycles();
			#endif

			if (*pLine == ' ')
				pLine++;
			if (*pLine != '(')
				ScriptError("Syntax error: callback (<var_int func [, var_int params])");
			else 
				pLine++;

			// get the pointer to the function
			int Exist=GetKeyword();
			int * func = (int *) pLastVariable; 
			if (Exist != VAR_INT)
				ScriptError("Syntax error: callback (<var_int func [, var_int params])");

			if (*pLine == ')')
			{
				// the callback hasn't any parameters
				pLine++;
				DWORD stackLevel = gCurrentHeapStackLevel;
				gos_PushCurrentHeap(ClientHeap);
				SavePosition();
				result = ((GOSSCRIPTCALLBACK)func)((void *)pScript->Instance,0,0);
				RestorePosition();
				gos_PopCurrentHeap();
				if (stackLevel > gCurrentHeapStackLevel)
					ScriptError("During this callback, the heap stack was push more times than it was popped");
				else
				if (stackLevel < gCurrentHeapStackLevel)
					ScriptError("During this callback, the heap stack was popped more times than it was pushed");
				// did those bastards end the script inside the callback?
#ifdef _ARMOR
				SCRIPT * ptr = pListofScripts;
				while(ptr)
				{
					if (ptr == pScript)
						break;
					ptr = ptr->pNext;
				}
				if (ptr == NULL)
					STOP(("Cannot gosScript_EndScript within a callback. Signal script via callback return value"));
#endif

			}
			else
			{
				// if parameters do not follow, the syntax must be wrong
				if (*pLine != ',')
					ScriptError("Syntax error: callback (<var_int func [, var_int params])");

				// count parameters and pass to function
				void * arg[16];
				for(int i=0; i < 16; i++)
					arg[i] = 0;
				int args = 0;
				char * str = NULL;
				char stringTmp[15][128];
				while(*pLine == ',')
				{

					if (args > 15)
						ScriptError("Syntax error: callbacks can have no more than 16 parameters");
					pLine++;
					int valid = GetKeyword();
					if (valid == VAR_PANE)
					{
						arg[args] = (void *) ((gos_Pane *) *pLastVariable)->GetSurface()->GetDataPointer();
					}
					else
					if (valid != -1)
					{
						arg[args] = (void *) pLastVariable;
					}
					else
					if ((str = GetString()) != NULL)
					{
						strncpy(stringTmp[args], str, 127);
						arg[args] = (void *) stringTmp[args];
					}
					else
					{
						arg[args] = (void *) GetExpression();
					}
					args++;
				}
				// check for closing parathesis and make the call!
				if (*pLine == ' ')
					pLine++;
				if (*pLine != ')')
					ScriptError("Syntax error: callback (<var_int func [, var_int params])");
				else
				{
					pLine++;
					DWORD stackLevel = gCurrentHeapStackLevel;
					gos_PushCurrentHeap(ClientHeap);
					SavePosition();
					result = ((GOSSCRIPTCALLBACK)func)((void *)pScript->Instance, args, arg);
					RestorePosition();
					gos_PopCurrentHeap();
					if (stackLevel > gCurrentHeapStackLevel)
						ScriptError("During this callback, the heap stack was push more times than it was popped");
					else
					if (stackLevel < gCurrentHeapStackLevel)
						ScriptError("During this callback, the heap stack was popped more times than it was pushed");
					// did those bastards end the script inside the callback?
#ifdef _ARMOR
					SCRIPT * ptr = pListofScripts;
					while(ptr)
					{
						if (ptr == pScript)
							break;
						ptr = ptr->pNext;
					}
					if (ptr == NULL)
						STOP(("Cannot gosScript_EndScript within a callback. Signal script via callback return value"));
#endif

				}

				#ifdef LAB_ONLY
				TimeScriptsCallbacks+=GetCycles()-StartTime;
				#endif
			}	
			return result;
		}
//
// GetKeyState - returns true if key is down
//
		case ROUTINE_GETKEYSTATE:
		{
			int KeyName=GetExpression();

			if( KeyName<0 || KeyName>255 )
				ScriptError("Expected a KeyNumber (0-255), found '%d'",KeyName );

			gosEnum_KeyStatus ks=gos_GetKeyStatus((gosEnum_KeyIndex)KeyName);
			return (ks==KEY_PRESSED || ks==KEY_HELD) ? 1 : 0;
		}
//
// GetKeyPressed - returns true if key just pressed
//
		case ROUTINE_GETKEYPRESSED:
		{
			int KeyName=GetExpression();

			if( KeyName<0 || KeyName>255 )
				ScriptError("Expected a KeyNumber (0-255), found '%d'",KeyName );

			gosEnum_KeyStatus ks=gos_GetKeyStatus((gosEnum_KeyIndex)KeyName);
			return (ks==KEY_PRESSED) ? 1 : 0;
		}
		case ROUTINE_GETVOLUME:
		{
			if (*pLine == ' ')
				pLine++;
			if (*pLine != '(')
				ScriptError("Syntax Error: GetVolume(var_int channel)");
			else
				pLine++;
			int chan = GetExpression();
			if (*pLine == ' ')
				pLine++;
			if (*pLine != ')')
				ScriptError("Syntax Error: GetVolume(var_int channel)");
			else
				pLine++;
			float val;
			gosAudio_GetChannelSlider(chan, gosAudio_Volume, &val);
			return (unsigned int) (val * 100);
		}
		case ROUTINE_GETPANNING:
		{
			if (*pLine == ' ')
				pLine++;
			if (*pLine != '(')
				ScriptError("Syntax Error: GetPanning(var_int channel)");
			else
				pLine++;
			int chan = GetExpression();
			if (*pLine == ' ')
				pLine++;
			if (*pLine != ')')
				ScriptError("Syntax Error: GetPanning(var_int channel)");
			else
				pLine++;
			float val;
			gosAudio_GetChannelSlider(chan, gosAudio_Panning, &val);
			return (unsigned int) (val * 100);
		}
		case ROUTINE_GETFREQUENCY:
		{
			if (*pLine == ' ')
				pLine++;
			if (*pLine != '(')
				ScriptError("Syntax Error: GetFrequency(var_int channel)");
			else
				pLine++;
			int chan = GetExpression();
			if (*pLine == ' ')
				pLine++;
			if (*pLine != ')')
				ScriptError("Syntax Error: GetFrequency(var_int channel)");
			else
				pLine++;
			float val;
			gosAudio_GetChannelSlider(chan, gosAudio_Frequency, &val);
			return (unsigned int) (val * 100);
		}
		case ROUTINE_GETSIZE:
		{
			if (*pLine == ' ')
				pLine++;
			if (*pLine != '(')
				ScriptError("Syntax Error: getsize(<var_gaf>)");
			else
				pLine++;
			int kw = GetKeyword();
			if (kw != VAR_GAF)
				ScriptError("Syntax Error: getsize(<var_gaf>)");
			if (*pLine == ' ')
				pLine++;
			if (*pLine != ')')
				ScriptError("Syntax Error: getsize(<var_gaf>)");
			else
				pLine++;
			int val;

			if (*pLastVariable == 0)
				ScriptError("Attempt to getsize on an undefined gaf");

			gos_GetGAFSize((HGOSGAF)*pLastVariable,NULL,NULL,&val);
			return val;
		}
		case ROUTINE_GETHEIGHT:
		{
			if (*pLine == ' ')
				pLine++;
			#ifdef _DEBUG
			if (*pLine != '(')
				ScriptError("Syntax Error: getheight(<var_gaf> or <var_bitmap> or <var_pane> or <var_movie>)");
			#endif
			pLine++;
			int kw = GetKeyword();
			switch(kw)
			{
				case VAR_GAF:
					int val;
					#ifdef _DEBUG
					if (*pLastVariable == 0)
						ScriptError("Attempt to getheight on an undefined gaf");
					#endif
					gos_GetGAFSize((HGOSGAF)*pLastVariable,NULL,&val,NULL);
					result = val;
					break;
				case VAR_PANE:
					#ifdef _DEBUG
					if (*pLastVariable == 0)
						ScriptError("Attempt to getheight on an undefined pane");
					#endif
					result = ((gos_Pane *) *pLastVariable)->m_pTextureList->m_height;
					break;
				case VAR_BITMAP:
					#ifdef _DEBUG
					if (*pLastVariable == 0)
						ScriptError("Attempt to getheight on an undefined bitmap");
					#endif
					result = gos_GetSurfaceHeight((HGOSSURFACE)*pLastVariable);
					break;
				case VAR_MOVIE:
					#ifdef _DEBUG
					if (*pLastVariable == 0)
						ScriptError("Attempt to getheight on an undefined movie");
					#endif
					gosVideo_ResourceInfo ri;
					gosVideo_GetResourceInfo((HGOSVIDEO)*pLastVariable, &ri);
					result = ri.dwHeight;
					break;
				default:
					ScriptError("Syntax Error: getheight(<var_gaf> or <var_bitmap> or <var_pane> or <var_movie>)");
					break;
			}
			if (*pLine == ' ')
				pLine++;
			#ifdef _DEBUG
			if (*pLine != ')')
				ScriptError("Syntax Error: getheight(<var_gaf> or <var_bitmap> or <var_pane> or <var_movie>)");
			#endif
			pLine++;

			return result;
		}
		case ROUTINE_GETWIDTH:
		{
			if (*pLine == ' ')
				pLine++;
			#ifdef _DEBUG
			if (*pLine != '(')
				ScriptError("Syntax Error: getwidth(<var_gaf> or <var_bitmap> or <var_pane> or <var_movie>)");
			#endif
			pLine++;
			int kw = GetKeyword();
			switch(kw)
			{
				case VAR_GAF:
					int val;
					#ifdef _DEBUG
					if (*pLastVariable == 0)
						ScriptError("Attempt to getwidth on an undefined gaf");
					#endif
					gos_GetGAFSize((HGOSGAF)*pLastVariable,&val,NULL,NULL);
					result = val;
					break;
				case VAR_PANE:
					#ifdef _DEBUG
					if (*pLastVariable == 0)
						ScriptError("Attempt to getwidth on an undefined pane");
					#endif
					result = ((gos_Pane *) *pLastVariable)->m_pTextureList->m_width;
					break;
				case VAR_BITMAP:
					result = gos_GetSurfaceWidth((HGOSSURFACE)*pLastVariable);
					#ifdef _DEBUG
					if (*pLastVariable == 0)
						ScriptError("Attempt to getwidth on an undefined bitmap");
					#endif
					break;
				case VAR_MOVIE:
					#ifdef _DEBUG
					if (*pLastVariable == 0)
						ScriptError("Attempt to getwidth on an undefined movie");
					#endif
					gosVideo_ResourceInfo ri;
					gosVideo_GetResourceInfo((HGOSVIDEO)*pLastVariable, &ri);
					result = ri.dwWidth;
					break;
				default:
					ScriptError("Syntax Error: getwidth(<var_gaf> or <var_bitmap> or <var_pane> or <var_movie>)");
					break;
			}
			if (*pLine == ' ')
				pLine++;
			#ifdef _DEBUG
			if (*pLine != ')')
				ScriptError("Syntax Error: getwidth(<var_gaf> or <var_bitmap> or <var_pane>)");
			#endif
			pLine++;
			return result;
		}
		case ROUTINE_GETSTATUS:
		{
			if (*pLine == ' ')
				pLine++;
			if (*pLine != '(')
				ScriptError("Syntax error: getstatus (<VAR_MOVIE> or <VAR_INT>)");
			else
				pLine++;
			long * tmp = pLastVariable;
			int Exist=GetKeyword();
			if (*pLine == ' ')
				pLine++;
			if (Exist == -1 || Exist == VAR_INT)
			{
				int expr;
				if (Exist == VAR_INT)
					expr = *pLastVariable;
				else
					expr = GetExpression();
				// GAH! how can I get the result to the script
				switch(gosAudio_GetChannelPlayMode(expr))
				{
				case gosAudio_PlayOnce:
					result = 1;
					break;
				case gosAudio_Pause:
					result = 2;
					break;
				case gosAudio_Stop:
					result = 3;
					break;
				case gosAudio_Loop:
					result = 4;
					break;
				}
			}
			else
			{
				if (Exist != VAR_MOVIE && Exist != VAR_PANE)
					ScriptError("Syntax error: getstatus (<VAR_MOVIE>, <VAR_PANE> or <VAR_INT>)");
				else
				{
					// GAH! how can I get the result to the script
					HGOSVIDEO hvid = NULL;
					if (Exist == VAR_PANE)
						hvid = (HGOSVIDEO) (long) ((gos_Pane *)*pLastVariable)->hVideo;
					else
						hvid = (HGOSVIDEO) *pLastVariable;
					gosVideo_ResourceInfo gv_ri;
					gosVideo_GetResourceInfo(hvid, &gv_ri);
					switch(gv_ri.ePlayStatus)
					{
					case	gosVideo_PlayOnceHold:
					case	gosVideo_PlayOnceHide:
					case	gosVideo_Loop:
						result = 1;
						break;
					case	gosVideo_Pause:
						result = 2;
						break;
					case	gosVideo_Stop:
						result = 3;
						break;
					}
				}
			}
			pLastVariable = tmp;
			if (*pLine != ')')
				ScriptError("Syntax error: getstatus (<VAR_MOVIE>, <VAR_PANE> or <VAR_INT>)");
			pLine++;
			return result;
		}
		case ROUTINE_SETVOLUME:
		{
			if (*pLine == ' ')
				pLine++;
			if (*pLine != '(')
				ScriptError("Syntax Error: SetVolume(var_int channel, <var_int> percent)");
			else
				pLine++;

			int chan = 0 ;
			HGOSVIDEO theMovie = NULL;
			int kw = GetKeyword();
			if (kw == VAR_MOVIE)
			{
				theMovie = (HGOSVIDEO) *pLastVariable;
			}
			else 
			if (kw == VAR_PANE)
			{
				theMovie = (HGOSVIDEO) (long) ((gos_Pane *)*pLastVariable)->hVideo;
				if (!theMovie)
					ScriptError("Attempting to set volume on a non-movie pane");
			}

			if (kw == VAR_INT || kw == -1)
				chan = GetExpression();
			if (*pLine == ' ')
				pLine++;
			if (*pLine != ',')
				ScriptError("Syntax Error: SetVolume(var_int channel, <var_int> percent)");
			else
				pLine++;
			int val = GetExpression();
			if (*pLine != ')')
				ScriptError("Syntax Error: SetVolume(var_int channel, <var_int> percent)");
			else
				pLine++;

			if (theMovie)
				gosVideo_Command(theMovie, gosVideo_Volume, (float) val / 100.0f );
			else
				gosAudio_SetChannelSlider(chan, gosAudio_Volume, (float) val / 100.0f );
			return 0;
		}
		case ROUTINE_SETPANNING:
		{
			if (*pLine == ' ')
				pLine++;
			if (*pLine != '(')
				ScriptError("Syntax Error: SetPanning(var_int channel, <var_int> -100 to +100)");
			else
				pLine++;
			int chan = GetExpression();
			if (*pLine == ' ')
				pLine++;
			if (*pLine != ',')
				ScriptError("Syntax Error: SetPanning(var_int channel, <var_int> -100 to +100)");
			else
				pLine++;
			int val = GetExpression();
			if (*pLine != ')')
				ScriptError("Syntax Error: SetPanning(var_int channel, <var_int> -100 to +100)");
			else
				pLine++;
			gosAudio_SetChannelSlider(chan, gosAudio_Panning, (float)val/100.0f);
			return 0;
		}
		case ROUTINE_SETFREQUENCY:
		{
			if (*pLine == ' ')
				pLine++;
			if (*pLine != '(')
				ScriptError("Syntax Error: SetFrequency(var_int channel, <var_int> percent)");
			else
				pLine++;
			int chan = GetExpression();
			if (*pLine == ' ')
				pLine++;
			if (*pLine != ',')
				ScriptError("Syntax Error: SetFrequency(var_int channel, <var_int> percent)");
			else
				pLine++;
			int val = GetExpression();
			if (*pLine != ')')
				ScriptError("Syntax Error: SetFrequency(var_int channel, <var_int> percent)");
			else
				pLine++;
			gosAudio_SetChannelSlider(chan, gosAudio_Frequency, (float)val/100.0f);
			return 0;
		}
		case ROUTINE_SETPROPERTIES:
		{
			if (*pLine == ' ')
				pLine++;
			if (*pLine != '(')
				ScriptError("Syntax Error: SetProperties(var_int channel, <var_int> flag1 [| flag2,...])");
			else
				pLine++;
			int chan = GetExpression();
			if (*pLine == ' ')
				pLine++;
			if (*pLine != ',')
				ScriptError("Syntax Error: SetProperties(var_int channel, <var_int> flag1 [| flag2,...])");
			else
				pLine++;
			int val = GetExpression();
			if (*pLine != ')')
				ScriptError("Syntax Error: SetProperties(var_int channel, <var_int> flag1 [| flag2,...])");
			else
				pLine++;
			int tmp = val & 15;
			gosAudio_AllocateChannelSliders(chan, tmp);
			return 0;
		}
		case ROUTINE_ABSOLUTEVALUE:
		{
			if (*pLine == ' ')
				pLine++;
			if (*pLine != '(')
				ScriptError("Syntax Error: abs(expr)");
			else
				pLine++;
			int val = GetExpression();
			if (*pLine == ' ')
				pLine++;
			if (*pLine != ')')
				ScriptError("Syntax Error: abs(expr)");
			else
				pLine++;
			return abs(val);
		}
		case ROUTINE_GETPIXEL:
		{
			long* tmp = pLastVariable;
			if (*pLine == ' ')
				pLine++;
			if (*pLine != '(')
				ScriptError("Syntax Error: getpixel(var_bitmap,x,y)");
			else
				pLine++;
			if (*pLine == ' ')
				pLine++;
			
			int kw = GetKeyword();
			HGOSSURFACE surf;

			surf = (HGOSSURFACE) *pLastVariable;
			if (*pLastVariable == 0)
				ScriptError("Attempt to getpixel on an undefined bitmap or pane");
			if (kw == VAR_PANE)
			{
				surf = (HGOSSURFACE) ((gos_Pane *) *pLastVariable)->GetSurface();
				if (!surf)
					ScriptError("You cannot perform getpixel on a nonvolitile pane");
			}
			else
			if (kw != VAR_BITMAP)
				ScriptError("Syntax Error: getpixel(var_bitmap,x,y)");

			if (*pLine == ' ')
				pLine++;
			if (*pLine == ',')
				pLine++;
			else
				ScriptError("Syntax Error: getpixel(var_bitmap,x,y)");
			if (*pLine == ' ')
				pLine++;
			int x = GetExpression();
			if (*pLine == ' ')
				pLine++;
			if (*pLine != ',')
				ScriptError("Syntax Error: getpixel(var_bitmap,x,y)");
			else
				pLine++;
			if (*pLine == ' ')
				pLine++;
			int y = GetExpression();
			if (*pLine != ')')
				ScriptError("Syntax Error: getpixel(var_bitmap,x,y)");
			else
				pLine++;
			pLastVariable = tmp;
			return gos_GetPixel(surf,x,y);;
		}
		case ROUTINE_MAKEINT:
		{
			if (*pLine == ' ')
				pLine++;
			if (*pLine != '(')
				ScriptError("Syntax Error: makeint(var_string)");
			else
				pLine++;
			const char * tmp = GetString();
			if (*pLine == ' ')
				pLine++;
			if (*pLine != ')')
				ScriptError("Syntax Error: makeint(var_string)");
			else
				pLine++;
			if (tmp == 0)
				result = 0;
			return atoi(tmp);
		}
		case ROUTINE_GETCHAR:
		{
			if (*pLine == ' ')
				pLine++;
			if (*pLine != '(')
				ScriptError("Syntax Error: getchar()");
			else
				pLine++;
			if (*pLine == ' ')
				pLine++;
			if (*pLine != ')')
				ScriptError("Syntax Error: getchar()");
			else
				pLine++;
#if 1
			int iRc = scriptLastKey & 0xff;			
			if (g_bLeadByte) {
				// current character is trail byte.
				iRc |= (g_bLeadByte) << 8;
				return iRc;
			}
			else if (LeadByteTable[((unsigned char)scriptLastKey)])
				return 0;	// it's leadbyte - ignore it.
			return iRc;
#else
			return scriptLastKey & 0xff;
#endif
		}

		case ROUTINE_GETKEY:
		{
			if (*pLine == ' ')
				pLine++;
			if (*pLine != '(')
				ScriptError("Syntax Error: getkey()");
			else
				pLine++;
			if (*pLine == ' ')
				pLine++;
			if (*pLine != ')')
				ScriptError("Syntax Error: getkey()");
			else
				pLine++;
			return scriptLastKey;
		}

		case ROUTINE_GETCTRLCHAR:
		{
			if (*pLine == ' ')
				pLine++;
			if (*pLine != '(')
				ScriptError("Syntax Error: getctrlchar()");
			else
				pLine++;
			if (*pLine == ' ')
				pLine++;
			if (*pLine != ')')
				ScriptError("Syntax Error: getctrlchar()");
			else
				pLine++;
			if ((scriptLastKey & 0xff0000) || (scriptLastKey & 0xff) == 0)
				result = (scriptLastKey & 0xff00) >> 8;
			else
				result = 0;
			break;
		}
		case ROUTINE_CHAR:
		{
			if (*pLine == ' ')
				pLine++;
			if (*pLine != '(')
				ScriptError("Syntax Error: char(\"<ascii>\")");
			else
				pLine++;
			unsigned char * string = (unsigned char*)GetString();
			if (string)
			{
				if (*pLine == ' ')
					pLine++;
				if (*pLine != ')')
					ScriptError("Syntax Error: char(\"<ascii>\")");
				if (LeadByteTable[string[0]])
					return ((string[0]<<8)+string[1]);
				else
					return string[0];
			}
			else
				ScriptError("Syntax Error: char(\"<ascii>\")");



			break;
		}
	  	default:
		{
			ScriptError("Function not yet implemented");
			break;
		}
	}
	return result;
}






int NextWordLength()
{
	BYTE* pTemp=(BYTE*)pLine+1;
	while( KeywordChar[*(BYTE*)pTemp] )			// Find length of .variable
	{
		pTemp++;
	}
	return (char*)pTemp-pLine;
}




int ResolveVariable(VARIABLE * pVar)
{
	pLastVariableObject = pVar;
	pLastVariable=(long *)&pVar->Value;
	pLine+=pVar->NameLength;
	while(1)
	{
		if (*pLine == ' ')
			pLine++;
		if (*pLine == '[')
		{
			pLine++;
			#ifdef _DEBUG
			if (pVar->ArraySize == 0)
			{
				pLine--;
				pLine-=pVar->NameLength;
				return -1;
//				ScriptError("Variable '%s' is not an array",pVar->Name);
			}
			#endif
			if (*pLine == ']')
			{
				pLine++;
				pLastVariable=(long *)pVar->pValues;
				return VAR_STRANGE;
			}
			pLastVariable = (long *)pVar;
			int index = GetNextExpression();
			#ifdef LAB_ONLY
			if( index < 0)
				ScriptError( "A negative index of %d is being used on array %s", index, pVar->Name );
			if( index >= pVar->ArraySize )
				ScriptError( "Index of %d is greater than or equal to %s's array size of %d", index, pVar->Name, pVar->ArraySize );
			if( *pLine != ']' )
				ScriptError("No closing bracket on array index reference");
			#endif
			pLine++;
			if( *pLine==' ' )
				pLine++;
			#ifdef _DEBUG
			if( *pLine=='[' )
				ScriptError( "Multi-dimensional arrays not supported" );
			#endif

			pLastVariableObjectIndex = index;
			pLastVariableObject=(VARIABLE *)pVar->pValues[index];
			pLastVariable=(long *)&pVar->pValues[index];

			if( pVar->Type == VAR_INT )
			{
				return VAR_INT;
			}
			else if( pVar->Type == VAR_FLOAT )
			{
				return VAR_FLOAT;
			}
			else
			{
				if (*pLine == '.')
				{
					pLine++;

					if( pVar->Type==VAR_POSITION )
					{
						if( KeywordChar[*(BYTE*)(pLine+1)]==0 )
						{
							BYTE member=*pLine++;
							if( member=='x' )
							{
								pLastVariable = (long*)&pVar->pPositions[index]->x;
								return VAR_INT;
							}
							if( member=='y' )
							{
								pLastVariable = (long*)&pVar->pPositions[index]->y;
								return VAR_INT;
							}
							if( member=='z' )
							{
								pLastVariable = (long*)&pVar->pPositions[index]->z;
								return VAR_INT;
							}
							ScriptError("Position doesn't have a member called that");
						}
					}

					if( pVar->Type==VAR_CUBE )
					{
						if( KeywordChar[*(BYTE*)(pLine+4)]==0 )
						{
							DWORD member=*(DWORD*)pLine;
							pLine+=4;
							if( member=='x.1p' )
							{
								pLastVariable = (long*)&pVar->pCubes[index]->p1.x;
								return VAR_INT;
							}
							if( member=='y.1p' )
							{
								pLastVariable = (long*)&pVar->pCubes[index]->p1.y;
								return VAR_INT;
							}
							if( member=='z.1p' )
							{
								pLastVariable = (long*)&pVar->pCubes[index]->p1.z;
								return VAR_INT;
							}
							if( member=='x.2p' )
							{
								pLastVariable = (long*)&pVar->pCubes[index]->p2.x;
								return VAR_INT;
							}
							if( member=='y.2p' )
							{
								pLastVariable = (long*)&pVar->pCubes[index]->p2.y;
								return VAR_INT;
							}
							if( member=='z.2p' )
							{
								pLastVariable = (long*)&pVar->pCubes[index]->p2.z;
								return VAR_INT;
							}
						}
						else
						{
							WORD wmember = *(WORD*)pLine;
							if (wmember == '1p')
							{
								pLine+= 2;
								pLastVariable = &halfwayHouse;
								*pLastVariable = (long)&pVar->pCube->p1;
								return VAR_POSITION;
							}
							else
							if (wmember == '2p')
							{
								pLine+= 2;
								pLastVariable = &halfwayHouse;
								*pLastVariable = (long)&pVar->pCube->p2;
								return VAR_POSITION;
							}
							
						}
						ScriptError("Error deciphering cube member");
					}

					if( pVar->Type == VAR_OBJECT )
					{
						#ifdef _DEBUG
						if ( ((OBJECT*)pVar->pValues[index])->pFunction == NULL)
							ScriptError("Attempted to reference a member of undefined object \"%s[%d]\"", pVar->Name, index);
						#endif
                        OBJECT* target = (OBJECT *) pVar->pValues[index];// by jcem
						pVar = ((OBJECT *) pVar->pValues[index])->pVariables;
						int retval = -1;
						LastVariableScope = SCOPE_OBJECT;
						int NextLength=NextWordLength();
						while(pVar)
						{
							if( pVar->NameLength==NextLength && Equals(pLine, pVar->Name) )
							{
								if ((retval = ResolveVariable(pVar)) != -1)
								{
									return retval;
								}
							}
							pVar = pVar->pNext;
						}
                        // from here by jcem
						if( 7==NextLength && Equals(pLine, "visible") )
						{
                            static int s_Visible = 0;
                            s_Visible = target->bActive;
							pLastVariable = (long*)&s_Visible;
							return VAR_INT;
						}
                        // to here by jcem

						static char tmp[128];
						memcpy(tmp, pLine, NextLength);
						tmp[NextLength] = 0;
						ScriptError("Cannot resolve variable reference \"%s\"", tmp);
						return -1;
					}
				}
				else
					return pVar->Type;
			}
		}
		else if( *pLine == '.' )
		{
			pLine++;

			if( pVar->Type==VAR_POSITION )
			{
				if( KeywordChar[*(BYTE*)(pLine+1)]==0 )
				{
					BYTE member=*pLine++;
					if( member=='x' )
					{
						pLastVariable = (long*)&pVar->pPosition->x;
						return VAR_INT;
					}
					if( member=='y' )
					{
						pLastVariable = (long*)&pVar->pPosition->y;
						return VAR_INT;
					}
					if( member=='z' )
					{
						pLastVariable = (long*)&pVar->pPosition->z;
						return VAR_INT;
					}
					ScriptError("Position doesn't have a member called that");
				}
			}
			if( pVar->Type==VAR_CUBE )
			{
				if( KeywordChar[*(BYTE*)(pLine+4)]==0 )
				{
					DWORD member=*(DWORD*)pLine;
					pLine+=4;
					if( member=='x.1p' )
					{
						pLastVariable = (long*)&pVar->pCube->p1.x;
						return VAR_INT;
					}
					if( member=='y.1p' )
					{
						pLastVariable = (long*)&pVar->pCube->p1.y;
						return VAR_INT;
					}
					if( member=='z.1p' )
					{
						pLastVariable = (long*)&pVar->pCube->p1.z;
						return VAR_INT;
					}
					if( member=='x.2p' )
					{
						pLastVariable = (long*)&pVar->pCube->p2.x;
						return VAR_INT;
					}
					if( member=='y.2p' )
					{
						pLastVariable = (long*)&pVar->pCube->p2.y;
						return VAR_INT;
					}
					if( member=='z.2p' )
					{
						pLastVariable = (long*)&pVar->pCube->p2.z;
						return VAR_INT;
					}
				}
				else
				{
					WORD wmember = *(WORD*)pLine;
					if (wmember == '1p')
					{
						pLine+= 2;
						pLastVariable = &halfwayHouse;
						*pLastVariable = (long)&pVar->pCube->p1;
						return VAR_POSITION;
					}
					else
					if (wmember == '2p')
					{
						pLine+= 2;
						pLastVariable = &halfwayHouse;
						*pLastVariable = (long)&pVar->pCube->p2;
						return VAR_POSITION;
					}
				}
				ScriptError("Error deciphering cube member");
			}

			int NextLength=NextWordLength();

			if (pVar->Type == VAR_OBJECT)
			{
				#ifdef _DEBUG
				if ( ((OBJECT*)pVar->Value)->pFunction == NULL)
					ScriptError("Attempted to reference a member of undefined object \"%s\"", ((OBJECT *)pVar->Name));
				#endif
                OBJECT* target = (OBJECT *) pVar->Value;// by jcem
				pVar = ((OBJECT *) pVar->Value)->pVariables;
				int retval = -1;
				LastVariableScope = SCOPE_OBJECT;
				while(pVar)
				{
					if( pVar->NameLength==NextLength && Equals(pLine, pVar->Name) )
					{
						if ((retval = ResolveVariable(pVar)) != -1)
						{
							return retval;
						}
					}
					pVar = pVar->pNext;
				}
                // from here by jcem
				if( 7==NextLength && Equals(pLine, "visible") )
				{
                    static int s_Visible = 0;
                    s_Visible = target->bActive;
					pLastVariable = (long*)&s_Visible;
					return VAR_INT;
				}
                // to here by jcem
				static char tmp[128];
				memcpy(tmp, pLine, NextLength);
				tmp[NextLength] = 0;
				ScriptError("Cannot resolve variable reference \"%s\"", tmp);
			}
			if( pVar->NameLength==NextLength && Equals(pLine, pVar->Name) )
			{
				return ResolveVariable((VARIABLE *)&pVar->Value);
			}
			return -1;
		}
		#ifdef _DEBUG
		else if (pVar->ArraySize != 0)
		{
			ScriptError("%s is an array! Please supply an index", pVar->Name);
			return -1;
		}
		#endif
		else
		{
			pLastVariableObjectIndex = -1;
			pLastVariable=(long *)&pVar->Value; 
			return pVar->Type;
		}
	}
}



