#include ".\loader.h"
#include "SocketModule.hpp"
#include "LuaFunctions.h"

// -- the debug handler routine
#ifndef RELEASE_VERSION
void Loader::lua_Debug_HookRoutine(lua_State *L, lua_Debug *ar)
{
	bool breakPointSignaled=false; // è stato o meno segnalato un breakpoint
	lua_getinfo(L, "S", ar);
	lua_getinfo(L, "l", ar);

	switch(ar->event) {
		case LUA_HOOKLINE:

			// logga la linea se siamo in debug mode
			if (dsock->isInDebugMode())
				dsock->logfile(false, "[EXEC]|| %0.9ld %s", ar->currentline, ar->source);

			//if (ar->source)
			//	PFrogConsole::instance()->addconsole(0, "HK: %s", ar->source);
			// è necessario segnalare dove ci troviamo
			if (_announceWhereIsDebugger) {
				sprintf(tmpbuffer, "310||%s||%d", ar->source, ar->currentline);
				dsock->socksend(0, tmpbuffer);
				_announceWhereIsDebugger=false;
			}

			// se vogliamo settare pausa e metterci in step by step, settala
			if (this->_wantSetPause) {

				this->_stepByStep=true;
				this->_doNextStep=false;
				this->_wantSetPause=false;
				this->_announceWhereIsDebugger=true;

			} else {

				// verifica se per questa linea e sorgente è specificato un breakpoint
				struct breakpoint *tmp=breakpoints;
				while (tmp) {
					if (strcmp(ar->source, tmp->file) == 0 && tmp->line == ar->currentline) {
						// breakpoint trovato, imposta la modalità step by step
						this->_stepByStep=true;
						this->_doNextStep=false;
						this->_announceWhereIsDebugger=true;
						break;
					}
					tmp=tmp->next;
				} // ciclo breakpoint

				// dici dov'è il debugger se dobbiamo dirlo
				if (_announceWhereIsDebugger) {
					sprintf(tmpbuffer, "310||%s||%d", ar->source, ar->currentline);
					dsock->socksend(0, tmpbuffer);
					_announceWhereIsDebugger=false;
				}

				// se è abilitata la modalità step-by-step e non abbiamo già segnalato un breakpoint
				// interrompi l'esecuzione fino a quando
				// non riceviamo il segnale di prossimo step

				if (this->_stepByStep && !breakPointSignaled) {
					// aspetta prossimo step
					while(	!this->_doNextStep && 
							this->_stepByStep && 
							!this->_shutDown &&
							dsock->isConnected()
						)
						Sleep(1);
					// ok, setta che vogliamo aspettare di nuovo il prox step
					this->_doNextStep=false;
					// e segniamo che al prox step vogliamo sapere la locazione, solo se siamo in modalità step
					// by step
					if (this->_stepByStep)
						this->_announceWhereIsDebugger=true;
				}

			} // if (!this->_wantSetPause) {


		break; // LUA_HOOKLINE
	}
} // lua_Debug_HookRoutine
#endif

// -- openresext(resourcename [,count_new_lines]) - torna la lunghezza del buffer allocato (false in caso di errore)
int Loader::lua_Function_OpenResExt(lua_State *pL)
{
	// controlla parametri
	if (!checkParams(pL, 1, 2, "openresext", false)) {
		lua_pushboolean(pL, false);
		return 1;
	}

	// risorsa da aprire
	int numpars = lua_gettop(pL);
	const char *resfile = lua_tostring(pL, 1);

	bool parseLines=false;

	if (numpars == 2) {
		parseLines=(lua_toboolean(pL, 2)==1?true:false);
	}


	// libera risorsa precedentemente allocata (se allocata)
	free(openResBuffer);
	openResBuffer=NULL;
	openResLength=0;

	// distrugge contatori linee allocate durante l'openres della risorsa
	if (openResLine) {
		for (unsigned int i=0; i < openResNumLines; i++)
			delete openResLine[i];
		free(openResLine);
		openResLine=NULL;
		openResNumLines=0;
	}

	// path dove cercare il file
	TCHAR lpFileName[512],lpFileName2[512];

	// extract exe path
	GetModuleFileName(NULL, lpFileName, 255);

	// get the last backslash
	for (int i=_tcslen(lpFileName)-1; i>=0; i--) {
		if ( lpFileName[i] == _T('\\') ) {
			_stprintf(lpFileName2, _T("%.*s"), i+1, lpFileName); 
			break;
		}
	}
	
#ifdef ARM
	TCHAR finalfname[1024];
	MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, resfile, -1, finalfname, 1024);
	_stprintf(lpFileName, _T("%s%s"), lpFileName2, finalfname); 
#else
	_stprintf(lpFileName, _T("%s%s"), lpFileName2, resfile); 
#endif


	// adesso proviamo ad aprire il file nelle risorse esterne
	FILE *fp = _tfopen(lpFileName, _T("rb"));
	// sanity
	if (!fp) {
		lua_pushboolean(pL, false);
		return 1;
	}

    fseek (fp, 0, SEEK_END);
    unsigned long size=ftell (fp);

	// sanity
	if (size == 0) {
		fclose(fp);
		lua_pushboolean(pL, false);
		return 1;
	}

    fseek (fp, 0, SEEK_SET);
	// alloca buffer e copia l'intero file
	openResLength=size;
	openResBuffer=(char *)malloc(openResLength);
	fread (openResBuffer,1,size,fp);
	fclose(fp);

	// se dobbiamo fare il parsing delle linee della risorsa, fallo ora
	if (parseLines)
		_ParseResLines();

	lua_pushnumber(pL, openResLength);
	return 1;
} // openresext


// -- openres(resourcename [,count_new_lines]) - torna la lunghezza del buffer allocato (false in caso di errore)
int Loader::lua_Function_OpenRes(lua_State *pL)
{
	// controlla parametri
	if (!checkParams(pL, 1, 2, "openres", false)) {
		lua_pushboolean(pL, false);
		return 1;
	}

	// risorsa da aprire
	int numpars = lua_gettop(pL);
	const char *resfile = lua_tostring(pL, 1);

	bool parseLines=false;

	if (numpars == 2) {
		parseLines=(lua_toboolean(pL, 2)==1?true:false);
	}


	// libera risorsa precedentemente allocata (se allocata)
	free(openResBuffer);
	openResBuffer=NULL;
	openResLength=0;

	// distrugge contatori linee allocate durante l'openres della risorsa
	if (openResLine) {
		for (unsigned int i=0; i < openResNumLines; i++)
			delete openResLine[i];
		free(openResLine);
		openResLine=NULL;
		openResNumLines=0;
	}

#ifdef ARM
	TCHAR finaltext[1024];
	MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, resfile, -1, finaltext, 1024);
#endif

	// adesso proviamo ad aprire il file nelle risorse
	bool loaded = true;

	LZArchive lza;
	LZItem lzi;

	// load and decompress the file
	if (lza.open(_T("fba.dat")) == false)
		loaded=false;
#ifdef ARM
	else if (lza.read(finaltext, &lzi) == false)
#else
	else if (lza.read(resfile, &lzi) == false)
#endif
		loaded=false;

	if (loaded) {
		// decomprimi
		lzi.decompress();
		unsigned char *buf = (unsigned char *)lzi.dBuffer();
		
		unsigned long b;

		// alloca buffer e copia la nostra risorsa
		openResLength=lzi.dSize();
		openResBuffer=(char *)malloc(openResLength);
		for (b=0; b < openResLength; b++)
			openResBuffer[b]=buf[b];


		// se dobbiamo fare il parsing delle linee della risorsa, fallo ora
		if (parseLines)
			_ParseResLines();
			

		lua_pushnumber(pL, openResLength);
		return 1;
	} else {
		PFrogConsole::instance()->addconsole(0, "OPENRES: UNABLE TO EXTRACT RESOURCE FILE %s!", resfile);
		SendErrorIDE(0, "ERR||OPENRES: UNABLE TO EXTRACT RESOURCE FILE %s!", resfile);
		lua_pushboolean(pL, false);
		return 1;
	}
} // openres

// effettua parsing linee file aperto con openres
void Loader::_ParseResLines()
{
	// conta e alloca new lines
	unsigned long truncat, start=0, lastBegin=0;
	bool foundEndLine = false, endOfFile=false;

	// cicla per tutta la stringa
	while (!endOfFile) {

		if (openResBuffer[start] == 13 && (start+1<openResLength) && openResBuffer[start+1] == 10) {
			// trovato chr(13)+chr(10)
			truncat=start-1;
			start+=2;
			foundEndLine=true;
		} else if (openResBuffer[start] == 13  || openResBuffer[start] == 10 ) {
			// trovato chr(13) o chr(10)
			truncat=start-1;
			start+=1;
			foundEndLine=true;
		} else if (start+1 >= openResLength) {
			// fine del file
			truncat=start;
			foundEndLine=true;
			endOfFile=true;
		}

		// se hai trovato fine riga, realloca struct
		if (foundEndLine) {
			++this->openResNumLines;
			this->openResLine = (struct _openResLine **)realloc(this->openResLine, sizeof(struct _openResLine *)*this->openResNumLines);
			// segna start ed end di questa linea
			this->openResLine[this->openResNumLines-1] = new _openResLine;
			this->openResLine[this->openResNumLines-1]->start=lastBegin;
			this->openResLine[this->openResNumLines-1]->end=truncat;
			// il prossimo partirà da qui
			lastBegin = start;
			foundEndLine=false;
		}
		++start;
	}
} // void Loader::_ParseResLines()

// -- getresline([num]) -- num assente, torna il conto
int Loader::lua_Function_GetResLine(lua_State *pL)
{
	// controlla parametri
	if (!checkParams(pL, 0, 1, "getresline", false)) {
		lua_pushboolean(pL, false);
		return 1;
	}

	int numpars = lua_gettop(pL);
	
	if (numpars == 0) {
		lua_pushnumber(pL, this->openResNumLines);
	} else {
		// recupera la linea specifica	
		unsigned int index=(unsigned int)lua_tonumber(pL, 1);
		if (index > openResNumLines-1) {
			// range error
			PFrogConsole::instance()->addconsole(0, "GETRESLINE: RANGE ERROR %d - (TOT: %ld)", index, this->openResNumLines);
			SendErrorIDE(0, "ERR||GETRESLINE: RANGE ERROR %d - (TOT: %ld)", index, this->openResNumLines);
			lua_pushboolean(pL, false);
		} else {
			// ritorna la linea richiesta
			unsigned long len = openResLine[index]->end - openResLine[index]->start +1;
			unsigned int c=0;

			char *tmpbuf = (char *)malloc(len);
			
			for (int b=openResLine[index]->start; b <= openResLine[index]->end; b++) {
				tmpbuf[c++]=openResBuffer[b];
			}

			lua_pushlstring(pL, (const char*)tmpbuf, len);

			free(tmpbuf);
			tmpbuf=NULL;
		}
	}
	
	return 1;

} // lua_Function_GetResLine

// -- getres([from, to]) - torna una stringa contenente i dati del buffer allocato con unpackres, da from a to
int Loader::lua_Function_GetRes(lua_State *pL)
{
	// controlla parametri
	if (!checkParams(pL, 0, 2, "getres", false)) {
		lua_pushboolean(pL, false);
		return 1;
	}

	int numpars = lua_gettop(pL);

	unsigned int from, to;

	if (numpars==0) {
		// torna TUTTA la stringa O_O
		from=0;
		to=openResLength;
	} else {
		// torna parte della stringa
		from=(unsigned int)lua_tonumber(pL, 1);
		to=(unsigned int)lua_tonumber(pL, 2);
	}

	if (from > to || from > openResLength || to > openResLength) {
		// range error
		PFrogConsole::instance()->addconsole(0, "GETRES: RANGE ERROR %d - %d (TOT: %ld)", from, to, openResLength);
		SendErrorIDE(0, "ERR||GETRES: RANGE ERROR %d - %d (TOT: %ld)", from, to, openResLength);
		lua_pushboolean(pL, false);
	} else {
		// torna il buffer interessato a lua
		unsigned int c=0;
		unsigned int final_length=to-from;
		char *tmp_buf = (char *)malloc(final_length);

		for (unsigned int a=from; a < to; a++)
			tmp_buf[c++]=openResBuffer[a];

		lua_pushlstring(pL, (const char *)tmp_buf, final_length);

		free(tmp_buf);
		tmp_buf=NULL;
	}

	return 1;
} // getres

// -- closeres()
int Loader::lua_Function_CloseRes(lua_State *pL)
{
	// cancella tutta i buffer allocati per le risorse, e stop
	if (this->openResBuffer) {
		free(this->openResBuffer);
		this->openResBuffer=NULL;
		this->openResLength=0;
		lua_pushboolean(pL, true);
	} else {
		lua_pushboolean(pL, false);
	}
	return 1;
} // closeres


// FILESYSTEM
// -- handle=openfile(filename
int Loader::lua_Function_OpenFile(lua_State *pL)
{
	// controlla parametri
	if (!checkParams(pL, 2, 3, "openfile", false)) {
		lua_pushboolean(pL, false);
		return 1;
	}

	const char *fname=lua_tostring(pL, 1);
	const char *mode=lua_tostring(pL, 2);
	bool get_from_ext_resources = false; // default

	int numpars = lua_gettop(pL);

	// il file dobbiamo aprirlo dalle risorse esterne
	if ( numpars == 3 )
		get_from_ext_resources=(lua_toboolean(pL, 3)==1?true:false);

	// prova ad aprire file
	int slot=fsystem->OpenFile(fname, mode, get_from_ext_resources);

	if (slot == -1) {
		PFrogConsole::instance()->addconsole(0, "OPENFILE - UNABLE TO OPEN FILE %s", fname);
		SendErrorIDE(0, "ERR||OPENFILE - UNABLE TO OPEN FILE %s", fname);
		lua_pushboolean(pL, false);
	} else
		lua_pushnumber(pL, slot);

	return 1;
} // openfile

// -- closefile(handle)
int Loader::lua_Function_CloseFile(lua_State *pL)
{
	// controlla parametri
	if (!checkParams(pL, 1, "closefile", false)) {
		lua_pushboolean(pL, false);
		return 1;
	}

	int index = (int)lua_tonumber(pL, 1);

	if ( !fsystem->CloseFile(index) ) {
		PFrogConsole::instance()->addconsole(0, "CLOSEFILE - UNABLE TO CLOSE FILE %d", index);
		SendErrorIDE(0, "ERR||CLOSEFILE - UNABLE TO CLOSE FILE %d", index);
		lua_pushboolean(pL, false);
	} else
		lua_pushboolean(pL, true);

	return 1;
} // closefile

// -- current_position = posfile(handle)
// -- posfile(handle, offset, origin)
int Loader::lua_Function_PosFile(lua_State *pL)
{
	// controlla parametri
	if (!checkParams(pL, 1, 3, "posfile", false)) {
		lua_pushboolean(pL, false);
		return 1;
	}

	int numpars = lua_gettop(pL);
	int handle = (int)lua_tonumber(pL, 1);
	long retval;

	if ( numpars == 1 ) {
		// get position
		retval = fsystem->FTell( handle );
	} else {
		// set position
		int offset = (long)lua_tonumber(pL, 2);
		int whence;
		const char *origin= (const char *)lua_tostring(pL, 3);
		if ( strcmp(origin, "s") == 0 )
			whence = SEEK_SET;
		else if ( strcmp(origin, "e") == 0 )
			whence = SEEK_END;
		else
			whence = SEEK_CUR;
		retval = fsystem->FSeek( handle, whence, offset );
	}

	lua_pushnumber(pL, retval);
	return 1;
} // posfile

// -- readfile(handle, numchars)
int Loader::lua_Function_ReadFile(lua_State *pL)
{
	// controlla parametri
	if (!checkParams(pL, 2, "readfile", false)) {
		lua_pushboolean(pL, false);
		return 1;
	}

	int index = (int)lua_tonumber(pL, 1);
	int numchars = (int)lua_tonumber(pL, 2);

	// alloca buffer
	char *tmpbuf=(char *)malloc(numchars+1);
	int numread = fsystem->ReadBytes(index, tmpbuf, numchars);
	
	if (numread == numchars) {
		lua_pushlstring(pL, (const char*)tmpbuf, numchars);
	} else {
		lua_pushboolean(pL, false);
		//PFrogConsole::instance()->addconsole(0, "READFILE: HANDLE %d UNABLE TO READ %d BYTES", index, numchars);
		//SendErrorIDE(0, "ERR||READFILE: HANDLE %d UNABLE TO READ %d BYTES", index, numchars);
	}

	free(tmpbuf);

	return 1;
} // readfile

// -- writefile(handle, "string")
int Loader::lua_Function_WriteFile(lua_State *pL)
{
	// controlla parametri
	if (!checkParams(pL, 2, "writefile", false)) {
		lua_pushboolean(pL, false);
		return 1;
	}

	int index = (int)lua_tonumber(pL, 1);
	const char *text= (const char *)lua_tostring(pL, 2);

	int numwritten = fsystem->WriteBytes(index, text, strlen(text));

	//if (numwritten != strlen(text)) {
		//PFrogConsole::instance()->addconsole(0, "WRITEFILE: HANDLE %d UNABLE TO WRITE %s", text);
		//SendErrorIDE(0, "ERR||WRITEFILE: HANDLE %d UNABLE TO WRITE %s", text);
	//}

	lua_pushboolean(pL, ((unsigned)numwritten == (unsigned)strlen(text)));
	return 1;
} // writefile

// -- fileexists(filename)
int Loader::lua_Function_FileExists(lua_State *pL)
{
	// controlla parametri
	if (!checkParams(pL, 1, "fileexists", false)) {
		lua_pushboolean(pL, false);
		return 1;
	}

	const char *filename= (const char *)lua_tostring(pL, 1);

	lua_pushboolean(pL, fsystem->Exists(filename));

	return 1;
} // fileexists

// -- deletefile(filename)
int Loader::lua_Function_DeleteFile(lua_State *pL)
{
	// controlla parametri
	if (!checkParams(pL, 1, "deletefile", false)) {
		lua_pushboolean(pL, false);
		return 1;
	}

	const char *filename= (const char *)lua_tostring(pL, 1);

	lua_pushboolean(pL, fsystem->Delete(filename));

	return 1;
} // deletefile


#ifdef ENABLE_TTF_EXTENSION

// -- loadfont(indexfont, fontname)
int Loader::lua_Function_LoadFont(lua_State *pL)
{
	int error;

	// controlla parametri
	if (!checkParams(pL, 1, 2, "loadfont", false)) {
		lua_pushboolean(pL, false);
		return 1;
	}

	// verifica se dobbiamo allocare nuove oggetti font
	int numpars = lua_gettop(pL);
	int index;
	const char *fontfile;

	// se abbiamo passato solo un parametro, vogliamo l'autoassegnazione di uno slot
	// quindi cerco uno slot libero
	if (numpars == 1) {
		// Cerca il primo slot libero e per default lasciamo uno slot fuori limite
		index = MAX_FONTS;
		for (int s=0; s < MAX_FONTS; s++) {
			if (!fontsInit[s]) { index=s; break; }
		}
		fontfile = lua_tostring(pL, 1);
	} else {
		index=(int)lua_tonumber(pL, 1);
		fontfile = lua_tostring(pL, 2);
	}

	// siamo negli indici consentiti
	if (index >= MAX_FONTS) {
		PFrogConsole::instance()->addconsole(0, "LOADFONT: OUTBOUND FONT INDEX %d - MAX: %d", index, MAX_FONTS);
		SendErrorIDE(0, "ERR||LOADFONT: OUTBOUND FONT INDEX %d - MAX: %d", index, MAX_FONTS);
		lua_pushboolean(pL, false);
		return 1;
	}


	// la prima cosa che vogliamo fare quando l'utente fa il loadfont, 
	// è inizializzare la libreria  truetype se non è ancora inizializzata
	if ( !this->ft_library ) {
		this->ft_library = new _ft_library;

		error = FT_Init_FreeType( &this->ft_library->lib );
		if (error) {
			
			delete this->ft_library ;
			this->ft_library =NULL;

			SendErrorIDE(0, "ERR||CANNOT INIT FREETYPE LIBRARY");
			PFrogConsole::instance()->addconsole(0, "CANNOT INIT FREETYPE LIBRARY");
			lua_pushboolean(pL, false);
			return 1;
		}
		PFrogConsole::instance()->addconsole(0, "FREE TYPE LIBRARY INITIALIZED");
		SendErrorIDE(3, "INF||FREE TYPE LIBRARY INITIALIZED");
	}
	

	// verifica se dobbiamo allocare nuovi fonts
	if (index+1 > maxAllocatedFonts) {
		PFrogConsole::instance()->addconsole(0, "REALLOCATE FONTS FROM %d TO %d", maxAllocatedFonts, index+1);
		SendErrorIDE(3, "INF||REALLOCATE FONTS FROM %d TO %d", maxAllocatedFonts, index+1);
		maxAllocatedFonts=index+1;

		fonts=(GameTTF **)realloc(fonts, sizeof(GameTTF *)*maxAllocatedFonts);
	}

	// se il font era già allocato, distruggilo
	if (fontsInit[index]) {
		delete fonts[index];
		fonts[index]=NULL;
		fontsInit[index]=false;
	}	

	// Crea l'oggetto font
	fonts[index]=new GameTTF(&this->ft_library->lib);

#ifdef ARM
	TCHAR finaltext[1024];
	MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, fontfile, -1, finaltext, 1024);
#endif

	// Carica il font nell'oggetto
	if (
#ifdef ARM
	fonts[index]->LoadFont(_T("fba.dat"), finaltext)
#else
	fonts[index]->LoadFont(_T("fba.dat"), _T(fontfile))
#endif	 
		) {
		PFrogConsole::instance()->addconsole(0, "LOADED FONT %d - %s", index, fontfile);
		SendErrorIDE(3, "INF||LOADED FONT %d - %s", index, fontfile);
		lua_pushnumber(pL, index);
	} else {
		PFrogConsole::instance()->addconsole(0, "CANNOT LOAD FONT %d - %s", index, fontfile);
		SendErrorIDE(0, "ERR||CANNOT LOAD FONT %d - %s", index, fontfile);
		lua_pushboolean(pL, false);
	}

	fontsInit[index]=true;

	return 1;
} // lua_Function_LoadFont

// -- setfont(indexfont, pixelsize, red, green, blue)
int Loader::lua_Function_SetFont(lua_State *pL)
{
	// controlla parametri
	if (!checkParams(pL, 5, "setfont", false)) {
		lua_pushboolean(pL, false);
		return 1;
	}

	int index=(int)lua_tonumber(pL, 1);
	int pixsize=(int)lua_tonumber(pL, 2);
	int red=(int)lua_tonumber(pL, 3);
	int green=(int)lua_tonumber(pL, 4);
	int blue=(int)lua_tonumber(pL, 5);

	// verifica se il font esiste
	if (index >= MAX_FONTS  || !fontsInit[index]) {
		PFrogConsole::instance()->addconsole(0, "FONT INDEX %d NOT EXISTS!", index);
		SendErrorIDE(0, "ERR||FONT INDEX %d NOT EXISTS!", index);
		lua_pushboolean(pL, false);
		return 1;
	}

	fonts[index]->SetSize(pixsize, 0, Color(red,green,blue), Color(0,0,0));

	lua_pushboolean(pL, true);
	return 1;
} // lua_Function_LoadFont

// -- drawtext(indexfont, x, y, text)
int Loader::lua_Function_DrawText(lua_State *pL)
{
	// controlla parametri
	if (!checkParams(pL, 4, "drawtext", true)) {
		lua_pushboolean(pL, false);
		return 1;
	}

	int index=(int)lua_tonumber(pL, 1);
	int x=(int)lua_tonumber(pL, 2);
	int y=(int)lua_tonumber(pL, 3);
	const char *text = lua_tostring(pL, 4);

	// verifica se il font esiste
	if (index >= MAX_FONTS  || !fontsInit[index]) {
		PFrogConsole::instance()->addconsole(0, "FONT INDEX %d NOT EXISTS!", index);
		SendErrorIDE(0, "ERR||FONT INDEX %d NOT EXISTS!", index);
		lua_pushboolean(pL, false);
		return 1;
	}

	fonts[index]->DrawText(DISPLAY, x, y, (char *)text);

	lua_pushboolean(pL, true);
	return 1;
} // lua_Function_DrawText

// -- textwidth(indexfont, text)
int Loader::lua_Function_TextWidth(lua_State *pL)
{
	// controlla parametri
	if (!checkParams(pL, 2, "textwidth", false)) {
		lua_pushboolean(pL, false);
		return 1;
	}

	int index=(int)lua_tonumber(pL, 1);
	const char *text = lua_tostring(pL, 2);

	// verifica se il font esiste
	if (index >= MAX_FONTS  || !fontsInit[index]) {
		PFrogConsole::instance()->addconsole(0, "FONT INDEX %d NOT EXISTS!", index);
		SendErrorIDE(0, "ERR||FONT INDEX %d NOT EXISTS!", index);
		lua_pushboolean(pL, false);
		return 1;
	}

	unsigned long width = fonts[index]->DrawText(NULL, 0, 0, (char *)text);

	lua_pushnumber(pL, width);
	return 1;
} // lua_Function_TextWidth

// -- destroyfont(indexfont)
int Loader::lua_Function_DestroyFont(lua_State *pL)
{
	// controlla parametri
	if (!checkParams(pL, 1, "destroyfont", false)) {
		lua_pushboolean(pL, false);
		return 1;
	}

	int index=(int)lua_tonumber(pL, 1);

	// verifica se il font esiste
	if (index >= MAX_FONTS  || !fontsInit[index]) {
		PFrogConsole::instance()->addconsole(0, "FONT INDEX %d NOT EXISTS!", index);
		SendErrorIDE(0, "ERR||FONT INDEX %d NOT EXISTS!", index);
		lua_pushboolean(pL, false);
		return 1;
	}
	// distruggi font
	delete fonts[index];
	fonts[index]=NULL;
	fontsInit[index]=false;

	lua_pushboolean(pL, true);
	return 1;
} // lua_Function_LoadFont

#endif	 // #ifdef ENABLE_TTF_EXTENSION




// -- loadgfxfont([gfxfontslot,] imageslot, charset, chars_space)
int Loader::lua_Function_LoadGfxFont(lua_State *pL) {

	// controlla parametri
	if (!checkParams(pL, 3, 4, "loadgfxfont", true)) {
		lua_pushboolean(pL, false);
		return 1;
	}

	int numpars = lua_gettop(pL);
	int index, indexpic, charspace, shift = 0;
	const char *charset;

	// se abbiamo passato solo un parametro, vogliamo l'autoassegnazione di uno slot
	// quindi cerco uno slot libero
	if (numpars == 3) {
		// Cerca il primo slot libero e per default lasciamo uno slot fuori limite
		index = MAX_GFX_FONTS;
		for (int s=0; s < MAX_GFX_FONTS; s++) {
			if (!gfxfontsInit[s]) { index=s; break; }
		}
		shift=-1;
	} else {
		index=(int)lua_tonumber(pL, 1);
	}
	indexpic=(int)lua_tonumber(pL, 2 + shift);
	charset=lua_tostring(pL, 3 + shift);
	charspace=(int)lua_tonumber(pL, 4 + shift);

	// verifica se l'immagine esiste
	if (indexpic < MAX_IMAGES && !imagesInit[indexpic]) {
		SendErrorIDE(0,"ERR||LoadGfxFont surface %d not exists!", indexpic);
		lua_pushboolean(pL, false);
		return 1;
	}

	// siamo negli indici consentiti
	if (index >= MAX_GFX_FONTS) {
		PFrogConsole::instance()->addconsole(0, "LOADGFXFONT: OUTBOUND FONT INDEX %d - MAX: %d", index, MAX_GFX_FONTS);
		SendErrorIDE(0, "ERR|LOADGFXFONT: OUTBOUND FONT INDEX %d - MAX: %d", index, MAX_GFX_FONTS);
		lua_pushboolean(pL, false);
		return 1;
	}
	// verifica se dobbiamo allocare nuovi gfxfonts
	if (index+1 > maxAllocatedGfxFonts) {
		PFrogConsole::instance()->addconsole(0, "REALLOCATE GFXFONT FROM %d TO %d", maxAllocatedGfxFonts, index+1);
		SendErrorIDE(3, "INF||REALLOCATE GFXFONT FROM %d TO %d", maxAllocatedGfxFonts, index+1);
		maxAllocatedGfxFonts=index+1;
		gfxfonts=(GameFont **)realloc(gfxfonts, sizeof(GameFont*)*maxAllocatedGfxFonts);
	}

	// se la gfx font era già allocata, distruggila
	if (gfxfontsInit[index]) {
		delete gfxfonts[index];
		gfxfonts[index]=NULL;
		gfxfontsInit[index]=false;
	}	

	// crea la gfx font specificata
	gfxfonts[index] = new GameFont(this, DISPLAY, this->images[indexpic], (char *)charset, this->transColor);
	gfxfonts[index]->SetSeparator(charspace);

	if (gfxfonts[index]) {
		PFrogConsole::instance()->addconsole(0, "CREATED GFXFONT %d", index);
		SendErrorIDE(3, "INF||CREATED GFXFONT %d", index);
		gfxfontsInit[index]=true;
		lua_pushnumber(pL, index);
	} else {
		PFrogConsole::instance()->addconsole(0, "CANNOT CREATE GFXFONT %d", index);
		SendErrorIDE(0, "ERR||CANNOT CREATE GFXFONT %d", index);
		gfxfontsInit[index]=false;
		lua_pushboolean(pL, false);
	}

	return 1;
} // lua_Function_LoadGfxFont

// -- drawgfxtext(gfxfontslot, x, y, testo, red, green, blue)
int Loader::lua_Function_DrawGfxText(lua_State *pL) {

	// controlla parametri
	if (!checkParams(pL, 4, 7, "drawgfxtext", true)) {
		lua_pushboolean(pL, false);
		return 1;
	}

	// verifica se la risorsa c'è !
	int index=(int)lua_tonumber(pL, 1);
	if (index >= MAX_GFX_FONTS || !gfxfontsInit[index]) {
		PFrogConsole::instance()->addconsole(0, "TRYING TO DRAW A GFXFONT NOT LOADED! %d", index);
		SendErrorIDE(0, "ERR||TRYING TO DRAW A GFXFONT NOT LOADED! %d", index);
		lua_pushboolean(pL, false);
		return 1;
	}

	int numpars = lua_gettop(pL);
	int x=(int)lua_tonumber(pL, 2);
	int y=(int)lua_tonumber(pL, 3);
	const char *text=(const char *)lua_tostring(pL, 4);
	if ( numpars == 7 ) {
		// color mode
		unsigned char red=(int)lua_tonumber(pL, 5);
		unsigned char green=(int)lua_tonumber(pL, 6);
		unsigned char blue=(int)lua_tonumber(pL, 7);
		gfxfonts[index]->DrawText(DISPLAY, x, y, Color(red, green, blue), false, (char *)text);
	} else {
		// direct mode
		gfxfonts[index]->DrawText(DISPLAY, x, y, 0, true, (char *)text);
	}
	return 0;
} // drawgfxtext

// -- gfxfontwidth(handle,text)
int Loader::lua_Function_GfxTextWidth(lua_State *pL) {

	// controlla parametri
	if (!checkParams(pL, 2, "gfxtextwidth", false)) {
		lua_pushboolean(pL, false);
		return 1;
	}

	int index=(int)lua_tonumber(pL,1);
	const char *text=(const char *)lua_tostring(pL, 2);

	// verifica se la risorsa c'è !
	if (index >= MAX_GFX_FONTS || !gfxfontsInit[index]) {
		PFrogConsole::instance()->addconsole(0, "TRYING TO GETWIDTH FROM A GFXFONT NOT LOADED! %d", index);
		SendErrorIDE(0, "ERR||TRYING TO GETWIDTH FROM A GFXFONT NOT LOADED! %d", index);
		lua_pushboolean(pL, false);
		return 1;
	}

	lua_pushnumber(pL, gfxfonts[index]->GetTextWidth(text));
	return 1;

} // lua_Function_GfxTextWidth

// -- destroygfxfont(gfxfontslot)
int Loader::lua_Function_DestroyGfxFont(lua_State *pL) {

	// controlla parametri
	if (!checkParams(pL, 1, "destroygfxfont", false)) {
		lua_pushboolean(pL, false);
		return 1;
	}

	int index=(int)lua_tonumber(pL,1);

	// siamo negli indici consentiti
	if (index >= MAX_GFX_FONTS) {
		PFrogConsole::instance()->addconsole(0, "DESTROYGFXFONT: OUTBOUND FONT INDEX %d - MAX: %d", index, MAX_GFX_FONTS);
		SendErrorIDE(0, "ERR||DESTROYGFXFONT: OUTBOUND FONT INDEX %d - MAX: %d", index, MAX_GFX_FONTS);
		lua_pushboolean(pL, false);
		return 1;
	}

	// distruggi il font
	if (gfxfontsInit[index]) {
		delete gfxfonts[index];
		gfxfonts[index]=NULL;
		gfxfontsInit[index]=false;
	}	

	lua_pushboolean(pL, true);
	return 1;

} // destroygfxfont


// Gamegrids
#ifdef ENABLE_GAMEGRID

// destroygrid(index)
int Loader::lua_Function_DestroyGrid(lua_State *pL)
{
	// controlla parametri
	if (!checkParams(pL, 1, "destroygrid", false)) {
		lua_pushboolean(pL, false);
		return 1;
	}

	int index=(int)lua_tonumber(pL,1);

	// siamo negli indici consentiti
	if (index >= MAX_GAMEGRIDS) {
		PFrogConsole::instance()->addconsole(0, "DESTROYGRID: OUTBOUND GRIDS INDEX %d - MAX: %d", index, MAX_GAMEGRIDS);
		SendErrorIDE(0, "ERR||DESTROYGRID: OUTBOUND GRIDS INDEX %d - MAX: %d", index, MAX_GAMEGRIDS);
		lua_pushboolean(pL, false);
		return 1;
	}

	// distruggi la griglia
	if (gamegridsInit[index]) {
		delete gamegrids[index];
		gamegrids[index]=NULL;
		gamegridsInit[index]=false;
	}	

	lua_pushboolean(pL, true);
	return 1;
} // destroygrid

// -- creategrid([indexgrid,] indeximage, cols, rows, cellwidth, cellheight)
int Loader::lua_Function_CreateGrid(lua_State *pL) {

	// controlla parametri
	if (!checkParams(pL, 5, 6, "creategrid", false)) {
		lua_pushboolean(pL, false);
		return 1;
	}

	int numpars = lua_gettop(pL);
	int index, indexpic, cols, rows, cellwidth, cellheight, shift = 0;

	// se abbiamo passato solo un parametro, vogliamo l'autoassegnazione di uno slot
	// quindi cerco uno slot libero
	if (numpars == 5) {
		// Cerca il primo slot libero e per default lasciamo uno slot fuori limite
		index = MAX_GAMEGRIDS;
		for (int s=0; s < MAX_GAMEGRIDS; s++) {
			if (!gamegridsInit[s]) { index=s; break; }
		}
		shift=-1;
	} else {
		index=(int)lua_tonumber(pL, 1);
	}
	indexpic=(int)lua_tonumber(pL, 2 + shift);
	cols=(int)lua_tonumber(pL, 3 + shift);
	rows=(int)lua_tonumber(pL, 4 + shift);
	cellwidth=(int)lua_tonumber(pL, 5 + shift);
	cellheight=(int)lua_tonumber(pL, 6 + shift);

	// verifica se l'immagine esiste
	if (indexpic >= MAX_IMAGES || !imagesInit[indexpic]) {
		SendErrorIDE(0,"ERR||GameGrid surface %d not exists!", indexpic);
		lua_pushboolean(pL, false);
		return 1;
	}

	// siamo negli indici consentiti
	if (index >= MAX_GAMEGRIDS) {
		PFrogConsole::instance()->addconsole(0, "CREATEINDEX: OUTBOUND GRID INDEX %d - MAX: %d", index, MAX_GAMEGRIDS);
		SendErrorIDE(0, "ERR|CREATEINDEX: OUTBOUND GRID INDEX %d - MAX: %d", index, MAX_GAMEGRIDS);
		lua_pushboolean(pL, false);
		return 1;
	}
	// verifica se dobbiamo allocare nuove gamegrid
	if (index+1 > maxAllocatedGameGrids) {
		PFrogConsole::instance()->addconsole(0, "REALLOCATE GAMEGRIDS FROM %d TO %d", maxAllocatedGameGrids, index+1);
		SendErrorIDE(3, "INF||REALLOCATE GAMEGRIDS FROM %d TO %d", maxAllocatedGameGrids, index+1);
		maxAllocatedGameGrids=index+1;
		gamegrids=(GameGrid **)realloc(gamegrids, sizeof(GameGrid*)*maxAllocatedGameGrids);
	}

	// se la grid era già allocata, distruggila
	if (gamegridsInit[index]) {
		delete gamegrids[index];
		gamegrids[index]=NULL;
		gamegridsInit[index]=false;
	}	

	// crea la grid specificata
	gamegrids[index]=new GameGrid(images[indexpic], cols, rows, cellwidth, cellheight); 
	if (gamegrids[index]) {
		PFrogConsole::instance()->addconsole(0, "CREATED GAMEGRID %d - %d, %d", index, cols, rows);
		SendErrorIDE(3, "INF||CREATED GAMEGRID %d - %d, %d", index, cols, rows);
		gamegridsInit[index]=true;
		lua_pushnumber(pL, index);
	} else {
		PFrogConsole::instance()->addconsole(0, "CANNOT CREATE GAMEGRID %d", index);
		SendErrorIDE(0, "ERR||CANNOT CREATE GAMEGRID %d", index);
		gamegridsInit[index]=false;
		lua_pushboolean(pL, false);
	}

	return 1;
}
// -- gridcell(indexgrid, col, row, newindex)
// -- index = gridcell(indexgrid, col, row)
int Loader::lua_Function_GridCell(lua_State *pL) {

	// controlla parametri
	if (!checkParams(pL, 3, 4, "gridcell", false)) {
		lua_pushboolean(pL, false);
		return 1;
	}

	int numpars = lua_gettop(pL);
	int index=(int)lua_tonumber(pL, 1);
	int col=(int)lua_tonumber(pL, 2);
	int row=(int)lua_tonumber(pL, 3);
	int newindex=(int)lua_tonumber(pL, 4);

	// verifica se la gamegrid esiste
	if (index >= MAX_GAMEGRIDS  || !gamegridsInit[index]) {
		PFrogConsole::instance()->addconsole(0, "GAMEGRID INDEX %d NOT EXISTS!", index);
		SendErrorIDE(0, "ERR||GAMEGRID INDEX %d NOT EXISTS!", index);
		lua_pushboolean(pL, false);
		return 1;
	}

	// setta o getta index
	if (numpars == 3) {
			lua_pushnumber(pL, gamegrids[index]->GetCell(col, row));
	} else {
		if ( !gamegrids[index]->SetCell(col, row, newindex) ) {
			PFrogConsole::instance()->addconsole(0, "CANNOT SET CELL INDEX %d, %d - %d", row, col, newindex);
			SendErrorIDE(0, "ERR||CANNOT SET CELL INDEX %d, %d - %d", row, col, newindex);
			lua_pushboolean(pL, false);
		} else {
			lua_pushboolean(pL, true);
		}
	}

	return 1;
} // gridcell

// -- fillgrid(indexgrid, newindex [,fromx1, fromy1,fromx2,fromy2])
int Loader::lua_Function_FillGrid(lua_State *pL) {

	// controlla parametri
	if (!checkParams(pL, 2,6, "fillgrid", false)) {
		lua_pushboolean(pL, false);
		return 1;
	}

	int numpars = lua_gettop(pL);
	int index=(int)lua_tonumber(pL, 1);

	// verifica se la gamegrid esiste
	if (index >= MAX_GAMEGRIDS  || !gamegridsInit[index]) {
		PFrogConsole::instance()->addconsole(0, "GAMEGRID INDEX %d NOT EXISTS!", index);
		SendErrorIDE(0, "ERR||GAMEGRID INDEX %d NOT EXISTS!", index);
		lua_pushboolean(pL, false);
		return 1;
	}

	int cellindex=(int)lua_tonumber(pL, 2);

	if (numpars == 2) {
		gamegrids[index]->FillGrid(cellindex);
	} else {
		gamegrids[index]->FillGrid(cellindex, (int)lua_tonumber(pL, 3), (int)lua_tonumber(pL, 4),
			(int)lua_tonumber(pL, 5), (int)lua_tonumber(pL, 6));
	}

	lua_pushboolean(pL, true);
	return 1;
} // Loader::lua_Function_FillGrid(lua_State *pL) {


// -- drawgrid(indexgrid, x, y, width, height)
int Loader::lua_Function_DrawGrid(lua_State *pL) {

	// controlla parametri
	if (!checkParams(pL, 5, "drawgrid", true)) {
		lua_pushboolean(pL, false);
		return 1;
	}

	int index=(int)lua_tonumber(pL, 1);
	int x=(int)lua_tonumber(pL, 2);
	int y=(int)lua_tonumber(pL, 3);
	int width=(int)lua_tonumber(pL, 4);
	int height=(int)lua_tonumber(pL, 5);

	// verifica se la gamegrid esiste
	if (index >= MAX_GAMEGRIDS  || !gamegridsInit[index]) {
		PFrogConsole::instance()->addconsole(0, "GAMEGRID INDEX %d NOT EXISTS!", index);
		SendErrorIDE(0, "ERR||GAMEGRID INDEX %d NOT EXISTS!", index);
		lua_pushboolean(pL, false);
		return 1;
	}

	gamegrids[index]->draw(DISPLAY, x, y, width, height);

	lua_pushboolean(pL, true);
	return 1;
}

// -- gridworldx(indexgrid, [newx])
int Loader::lua_Function_GridWorldX(lua_State *pL) {
	
	// controlla parametri
	if (!checkParams(pL, 1, 2, "gridworldx", false)) {
		lua_pushboolean(pL, false);
		return 1;
	}

	// verifica se la gamegrid esiste
	int numpars = lua_gettop(pL);
	int index=(int)lua_tonumber(pL, 1);

	if (index >= MAX_GAMEGRIDS  || !gamegridsInit[index]) {
		PFrogConsole::instance()->addconsole(0, "GAMEGRID INDEX %d NOT EXISTS!", index);
		SendErrorIDE(0, "ERR||GAMEGRID INDEX %d NOT EXISTS!", index);
		lua_pushboolean(pL, false);
		return 1;
	}

	if (numpars == 1) {
		// get
		lua_pushnumber(pL, gamegrids[index]->WorldX() );
		return 1;
	} else {
		// set
		gamegrids[index]->WorldX( (int)lua_tonumber(pL, 2) );
		return 0;
	}
}

// -- gridworldy(indexgrid, [newy])
int Loader::lua_Function_GridWorldY(lua_State *pL) {
	
	// controlla parametri
	if (!checkParams(pL, 1, 2, "gridworldy", false)) {
		lua_pushboolean(pL, false);
		return 1;
	}

	// verifica se la gamegrid esiste
	int numpars = lua_gettop(pL);
	int index=(int)lua_tonumber(pL, 1);

	if (index >= MAX_GAMEGRIDS  || !gamegridsInit[index]) {
		PFrogConsole::instance()->addconsole(0, "GAMEGRID INDEX %d NOT EXISTS!", index);
		SendErrorIDE(0, "ERR||GAMEGRID INDEX %d NOT EXISTS!", index);
		lua_pushboolean(pL, false);
		return 1;
	}

	if (numpars == 1) {
		// get
		lua_pushnumber(pL, gamegrids[index]->WorldY() );
		return 1;
	} else {
		// set
		gamegrids[index]->WorldY( (int)lua_tonumber(pL, 2) );
		return 0;
	}
}

#endif // ENABLE_GAMEGRID


// -- screenwidth()
int Loader::lua_Function_ScreenWidth(lua_State *pL) {
	lua_pushnumber(pL, _screenWidth);
	return 1;
}

// -- screenwidth()
int Loader::lua_Function_ScreenHeight(lua_State *pL) {
	lua_pushnumber(pL, _screenHeight);
	return 1;
}

// -- quit()
int Loader::lua_Function_Quit(lua_State *pL) {
	this->_shutDown=true;

	lua_pushboolean(pL, true);
	return 1;
}

#ifdef ENABLE_AUDIO

// destroysound(index)
int Loader::lua_Function_DestroySound(lua_State *pL)
{
	// controlla parametri
	if (!checkParams(pL, 1, "destroysound", false)) {
		lua_pushboolean(pL, false);
		return 1;
	}

	int index=(int)lua_tonumber(pL,1);

	// siamo negli indici consentiti
	if (index >= MAX_SOUNDS) {
		PFrogConsole::instance()->addconsole(0, "DESTROYSOUND: OUTBOUND SOUNDS INDEX %d - MAX: %d", index, MAX_SOUNDS);
		SendErrorIDE(0, "ERR||DESTROYSOUND: OUTBOUND SOUNDS INDEX %d - MAX: %d", index, MAX_SOUNDS);
		lua_pushboolean(pL, false);
		return 1;
	}

	// distruggi il suono
	if (soundsInit[index]) {
		delete sounds[index];
		sounds[index]=NULL;
		soundsInit[index]=false;
	}	

	lua_pushboolean(pL, true);
	return 1;
} // destroysound

// destroymusic(index)
int Loader::lua_Function_DestroyMusic(lua_State *pL)
{
	// controlla parametri
	if (!checkParams(pL, 1, "destroymusic", false)) {
		lua_pushboolean(pL, false);
		return 1;
	}

	int index=(int)lua_tonumber(pL,1);

	// siamo negli indici consentiti
	if (index >= MAX_MUSICS) {
		PFrogConsole::instance()->addconsole(0, "DESTROYMUSIC: OUTBOUND MUSIC INDEX %d - MAX: %d", index, MAX_MUSICS);
		SendErrorIDE(0, "ERR||DESTROYMUSIC: OUTBOUND MUSIC INDEX %d - MAX: %d", index, MAX_MUSICS);
		lua_pushboolean(pL, false);
		return 1;
	}

	// distruggi la musica
	if (musicsInit[index]) {
		delete musics[index];
		musics[index]=NULL;
		musicsInit[index]=false;
	}	

	lua_pushboolean(pL, true);
	return 1;
} // destroymusic

// loadsound(index, filename)
int Loader::lua_Function_LoadSound(lua_State *pL)
{
	int c;

	// controlla parametri
	if (!checkParams(pL, 1, 2, "loadsound", false)) {
		lua_pushboolean(pL, false);
		return 1;
	}

	int numpars = lua_gettop(pL);
	int index;
	const char *wave;

	// se abbiamo passato solo un parametro, vogliamo l'autoassegnazione di uno slot
	// quindi cerco uno slot libero
	if (numpars == 1) {
		// Cerca il primo slot libero e per default lasciamo uno slot fuori limite
		index = MAX_SOUNDS;
		for (int s=0; s < MAX_SOUNDS; s++) {
			if (!soundsInit[s]) { index=s; break; }
		}
		wave = lua_tostring(pL, 1);
	} else {
		index=(int)lua_tonumber(pL, 1);
		wave = lua_tostring(pL, 2);
	}

	// siamo negli indici consentiti
	if (index >= MAX_SOUNDS) {
		PFrogConsole::instance()->addconsole(0, "LOADSOUND: OUTBOUND SOUND INDEX %d - MAX: %d", index, MAX_SOUNDS);
		SendErrorIDE(0, "ERR|LOADSOUND: OUTBOUND SOUND INDEX %d - MAX: %d", index, MAX_SOUNDS);
		lua_pushboolean(pL, false);
		return 1;
	}

	// aggiungi .wav al nome del file (se non c'è già)
	char *finalfile=(char *)malloc(strlen(wave)+5);

	if (strlen(wave) > 3 && tolower(wave[strlen(wave)-4])=='.' && tolower(wave[strlen(wave)-3])=='w' && 
		tolower(wave[strlen(wave)-2])=='a' && tolower(wave[strlen(wave)-1])=='v')
			sprintf(finalfile, "%s", wave);
	else
			sprintf(finalfile, "%s.wav", wave);

#ifdef ARM
	TCHAR finaltext[1024];
	MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, finalfile, -1, finaltext, 1024);
#endif
	

	// verifica se dobbiamo allocare nuovi suoni
	if (index+1 > maxAllocatedSounds) {
		PFrogConsole::instance()->addconsole(0, "REALLOCATE SOUNDS FROM %d TO %d", maxAllocatedSounds, index+1);
		SendErrorIDE(3, "INF||REALLOCATE SOUNDS FROM %d TO %d", maxAllocatedSounds, index+1);
		maxAllocatedSounds=index+1;

		sounds=(LZSound **)realloc(sounds, sizeof(LZSound *)*maxAllocatedSounds);
		soundsChannels=(hssChannel **)realloc(soundsChannels, sizeof(hssChannel *)*maxAllocatedSounds);

		// setta a NULL i canali dei suoni non ancora inizializzati
		for (c=0; c < maxAllocatedSounds; c++)
			if (!soundsInit[c])
				soundsChannels[c]=NULL;
	}

	// se il suono era già allocato, distruggilo
	if (soundsInit[index]) {
		if (soundsChannels[index])
			soundsChannels[index]->stop();
		delete sounds[index];
		sounds[index]=NULL;
		soundsInit[index]=false;
		soundsChannels[index]=NULL;
	}	

	// Carica il suono nell'index specificato
	sounds[index] = new LZSound();
#ifdef ARM
	sounds[index]->load(_T("fba.dat"), finaltext);
#else
	sounds[index]->load(_T("fba.dat"), finalfile);
#endif
	if (sounds[index]) {
		PFrogConsole::instance()->addconsole(0, "LOADED SOUND %d - %s", index, finalfile);
		SendErrorIDE(3, "INF||LOADED SOUND %d - %s", index, finalfile);
		soundsInit[index]=true;
		lua_pushnumber(pL, index);
	} else {
		PFrogConsole::instance()->addconsole(0, "CANNOT LOAD SOUND %d", index);
		SendErrorIDE(0, "ERR||CANNOT LOAD SOUND %d", index);
		soundsInit[index]=false;
		lua_pushboolean(pL, false);
	}

	free(finalfile);

	return 1;
} // loadsound

// loadmusic(index, filename)
int Loader::lua_Function_LoadMusic(lua_State *pL)
{
	int c;

	// controlla parametri
	if (!checkParams(pL, 1, 2, "loadmusic", false)) {
		lua_pushboolean(pL, false);
		return 1;
	}

	// verifica se dobbiamo allocare nuove oggetti sound
	int numpars = lua_gettop(pL);
	int index;
	const char *modfile;

	// se abbiamo passato solo un parametro, vogliamo l'autoassegnazione di uno slot
	// quindi cerco uno slot libero
	if (numpars == 1) {
		// Cerca il primo slot libero e per default lasciamo uno slot fuori limite
		index = MAX_MUSICS;
		for (int s=0; s < MAX_MUSICS; s++) {
			if (!musicsInit[s]) { index=s; break; }
		}
		modfile = lua_tostring(pL, 1);
	} else {
		index=(int)lua_tonumber(pL, 1);
		modfile = lua_tostring(pL, 2);
	}

	// siamo negli indici consentiti
	if (index >= MAX_MUSICS) {
		PFrogConsole::instance()->addconsole(0, "LOADMUSIC: OUTBOUND MUSIC INDEX %d - MAX: %d", index, MAX_MUSICS);
		SendErrorIDE(0, "ERR|LOADMUSIC: OUTBOUND MUSIC INDEX %d - MAX: %d", index, MAX_MUSICS);
		lua_pushboolean(pL, false);
		return 1;
	}

	// aggiungi .mod al nome del file
	char *finalfile=(char *)malloc(strlen(modfile)+5);

	if (strlen(modfile) > 3 && tolower(modfile[strlen(modfile)-4])=='.' && tolower(modfile[strlen(modfile)-3])=='m' && 
		tolower(modfile[strlen(modfile)-2])=='o' && tolower(modfile[strlen(modfile)-1])=='d')
			sprintf(finalfile, "%s", modfile);
	else
			sprintf(finalfile, "%s.mod", modfile);

	//sprintf(finalfile, "%s.mod", modfile);
#ifdef ARM
	TCHAR finaltext[1024];
	MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, finalfile, -1, finaltext, 1024);
#endif
	

	// verifica se dobbiamo allocare nuovi suoni
	if (index+1 > maxAllocatedMusics) {
		PFrogConsole::instance()->addconsole(0, "REALLOCATE MUSICS FROM %d TO %d", maxAllocatedMusics, index+1);
		SendErrorIDE(3, "INF||REALLOCATE MUSICS FROM %d TO %d", maxAllocatedMusics, index+1);
		maxAllocatedMusics=index+1;

		musics=(LZMusic **)realloc(musics, sizeof(LZMusic *)*maxAllocatedMusics);
		musicsChannels=(hssChannel **)realloc(musicsChannels, sizeof(hssChannel *)*maxAllocatedMusics);

		// setta a NULL i canali dei suoni non ancora inizializzati
		for (c=0; c < maxAllocatedMusics; c++)
			if (!musicsInit[c])
				musicsChannels[c]=NULL;
	}

	// se il suono era già allocato, distruggilo
	if (musicsInit[index]) {
		if (musicsChannels[index])
			musicsChannels[index]->stop();
		musicsChannels[index]=NULL;
		delete musics[index];
		musics[index]=NULL;
		musicsInit[index]=false;
	}	

	// Carica il suono nell'index specificato
	musics[index] = new LZMusic();
#ifdef ARM
	musics[index]->load(_T("fba.dat"), finaltext);
#else
	musics[index]->load(_T("fba.dat"), finalfile);
#endif
	if (musics[index]) {
		PFrogConsole::instance()->addconsole(0, "LOADED MUSIC %d - %s", index, finalfile);
		SendErrorIDE(3, "INF||LOADED MUSIC %d - %s", index, finalfile);
		musicsInit[index]=true;
		lua_pushnumber(pL, index);
	} else {
		PFrogConsole::instance()->addconsole(0, "CANNOT LOAD MUSIC %d", index);
		SendErrorIDE(0, "ERR||CANNOT LOAD MUSIC %d", index);
		musicsInit[index]=false;
		lua_pushboolean(pL, false);
	}

	free(finalfile);

	return 1;
} // loadmusic


// -- pausesound(index)
int Loader::lua_Function_PauseSound(lua_State *pL) {

	// controlla parametri
	if (!checkParams(pL, 1, "pausesound", false)) {
		lua_pushboolean(pL, false);
		return 1;
	}

	int index = (int)lua_tonumber(pL, 1);
	
	// verifica se la risorsa esiste
	if (index >= MAX_SOUNDS || !soundsInit[index]) {
		PFrogConsole::instance()->addconsole(0, "TRYING TO PAUSE A SOUND NOT LOADED! %d", index);
		SendErrorIDE(0, "ERR||TRYING TO PAUSE A SOUND NOT LOADED! %d", index);
		lua_pushboolean(pL, false);
		return 1;
	}

	if (soundsChannels[index])
		soundsChannels[index]->pause();

	lua_pushboolean(pL, true);
	return 1;
}

// -- resumesound(index)
int Loader::lua_Function_ResumeSound(lua_State *pL) {
	// controlla parametri
	if (!checkParams(pL, 1, "resumesound", false)) {
		lua_pushboolean(pL, false);
		return 1;
	}

	int index = (int)lua_tonumber(pL, 1);
	
	// verifica se la risorsa esiste
	if (index >= MAX_SOUNDS || !soundsInit[index]) {
		PFrogConsole::instance()->addconsole(0, "TRYING TO RESUME A SOUND NOT LOADED! %d", index);
		SendErrorIDE(0, "ERR||TRYING TO RESUME A SOUND NOT LOADED! %d", index);
		lua_pushboolean(pL, false);
		return 1;
	}

	if (soundsChannels[index])
		soundsChannels[index]->resume();

	lua_pushboolean(pL, true);
	return 1;
}
	

// -- playsound(index [,loop])
int Loader::lua_Function_PlaySound(lua_State *pL)
{
	// controlla parametri
	if (!checkParams(pL, 1, 2, "playsound", false)) {
		lua_pushboolean(pL, false);
		return 1;
	}

	int numpars = lua_gettop(pL);

	int index = (int)lua_tonumber(pL, 1);

	bool repeat = false;
	if (numpars == 2)
		repeat=(bool)(lua_toboolean(pL, 2)==1);
	
	// verifica se la risorsa esiste
	if (index >= MAX_SOUNDS || !soundsInit[index]) {
		PFrogConsole::instance()->addconsole(0, "TRYING TO PLAY A SOUND NOT LOADED! %d", index);
		SendErrorIDE(0, "ERR||TRYING TO PLAY A SOUND NOT LOADED! %d", index);
		lua_pushboolean(pL, false);
		return 1;
	}

	// suona risorsa
	sounds[index]->loop(repeat);
	soundsChannels[index]=hss_speaker->channel(hss_speaker->playSound(sounds[index]));
	PFrogConsole::instance()->addconsole(0, "PLAY SOUND: %d", index);
	SendErrorIDE(3, "INF||PLAY SOUND: %d", index);

	lua_pushboolean(pL, true);
	return 1;
}
// -- playmusic(index [,loop])
int Loader::lua_Function_PlayMusic(lua_State *pL)
{
	// controlla parametri
	if (!checkParams(pL, 1, 2, "playmusic", false)) {
		lua_pushboolean(pL, false);
		return 1;
	}

	int numpars = lua_gettop(pL);

	int index = (int)lua_tonumber(pL, 1);

	bool repeat=false;
	if (numpars == 2)
		repeat=(bool)(lua_toboolean(pL, 2)==1);
	
	// verifica se la risorsa esiste
	if (index >= MAX_MUSICS || !musicsInit[index]) {
		PFrogConsole::instance()->addconsole(0, "TRYING TO PLAY A MUSIC NOT LOADED! %d", index);
		SendErrorIDE(0, "ERR||TRYING TO PLAY A MUSIC NOT LOADED! %d", index);
		lua_pushboolean(pL, false);
		return 1;
	}

	// suona risorsa
	musics[index]->loop(repeat);
	musicsChannels[index]=hss_speaker->channel(hss_speaker->playMusic(musics[index]));
	PFrogConsole::instance()->addconsole(0, "PLAY MUSIC: %d", index);
	SendErrorIDE(3, "INF||PLAY MUSIC: %d", index);

	lua_pushboolean(pL, true);
	return 1;
}

// -- pausemusic(index)
int Loader::lua_Function_PauseMusic(lua_State *pL) {
	// controlla parametri
	if (!checkParams(pL, 1, "pausemusic", false)) {
		lua_pushboolean(pL, false);
		return 1;
	}

	int index = (int)lua_tonumber(pL, 1);
	
	// verifica se la risorsa esiste
	if (index >= MAX_MUSICS || !musicsInit[index]) {
		PFrogConsole::instance()->addconsole(0, "TRYING TO PAUSE A MUSIC NOT LOADED! %d", index);
		SendErrorIDE(0, "ERR||TRYING TO PAUSE A MUSIC NOT LOADED! %d", index);
		lua_pushboolean(pL, false);
		return 1;
	}

	if (musicsChannels[index])
		musicsChannels[index]->pause();

	lua_pushboolean(pL, true);
	return 1;
}

// -- resumemusic(index)
int Loader::lua_Function_ResumeMusic(lua_State *pL) {
	// controlla parametri
	if (!checkParams(pL, 1, "resumemusic", false)) {
		lua_pushboolean(pL, false);
		return 1;
	}

	int index = (int)lua_tonumber(pL, 1);
	
	// verifica se la risorsa esiste
	if (index >= MAX_MUSICS || !musicsInit[index]) {
		PFrogConsole::instance()->addconsole(0, "TRYING TO RESUME A MUSIC NOT LOADED! %d", index);
		SendErrorIDE(0, "ERR||TRYING TO RESUME A MUSIC NOT LOADED! %d", index);
		lua_pushboolean(pL, false);
		return 1;
	}

	if (musicsChannels[index])
		musicsChannels[index]->resume();

	lua_pushboolean(pL, true);
	return 1;
}

// -- stopmusic(index)
int Loader::lua_Function_StopMusic(lua_State *pL) {
	// controlla parametri
	if (!checkParams(pL, 1, "stopmusic", false)) {
		lua_pushboolean(pL, false);
		return 1;
	}

	int index = (int)lua_tonumber(pL, 1);
	
	// verifica se la risorsa esiste
	if (index >= MAX_MUSICS || !musicsInit[index]) {
		PFrogConsole::instance()->addconsole(0, "TRYING TO STOP A MUSIC NOT LOADED! %d", index);
		SendErrorIDE(0, "ERR||TRYING TO STOP A MUSIC NOT LOADED! %d", index);
		lua_pushboolean(pL, false);
		return 1;
	}

	if (musicsChannels[index])
		musicsChannels[index]->stop();

	lua_pushboolean(pL, true);
	return 1;
}

// -- stopsound(index)
int Loader::lua_Function_StopSound(lua_State *pL) {
	// controlla parametri
	if (!checkParams(pL, 1, "stopsound", false)) {
		lua_pushboolean(pL, false);
		return 1;
	}

	int index = (int)lua_tonumber(pL, 1);
	
	// verifica se la risorsa esiste
	if (index >= MAX_SOUNDS || !soundsInit[index]) {
		PFrogConsole::instance()->addconsole(0, "TRYING TO STOP A SOUND NOT LOADED! %d", index);
		SendErrorIDE(0, "ERR||TRYING TO STOP A SOUND NOT LOADED! %d", index);
		lua_pushboolean(pL, false);
		return 1;
	}

	if (soundsChannels[index])
		soundsChannels[index]->stop();

	lua_pushboolean(pL, true);
	return 1;
}

// -- musicvolume(index)
// -- musicvolume(index, newvolume)
int Loader::lua_Function_MusicVolume(lua_State *pL) {
	
	// controlla parametri
	if (!checkParams(pL, 1, 2, "musicvolume", false)) {
		lua_pushboolean(pL, false);
		return 1;
	}

	// verifica se la risorsa c'è !
	int numpars = lua_gettop(pL);
	int index=(int)lua_tonumber(pL, 1);
	if (index >= MAX_MUSICS || !musicsInit[index]) {
		PFrogConsole::instance()->addconsole(0, "TRYING TO MUSICVOLUME A SOUND NOT LOADED! %d", index);
		SendErrorIDE(0, "ERR||TRYING TO MUSICVOLUME A SOUND NOT LOADED! %d", index);
		lua_pushboolean(pL, false);
		return 1;
	}

	if (numpars == 1) {
		// get
		lua_pushnumber(pL, 
			(musicsChannels[index] ? musicsChannels[index]->volume() : 0)
			);
		return 1;
	} else {
		// set
		if (musicsChannels[index])
			musicsChannels[index]->volume((int)lua_tonumber(pL, 2));
		return 0;
	}
}

// -- soundvolume(index)
// -- soundvolume(index, newvolume)
int Loader::lua_Function_SoundVolume(lua_State *pL) {
	// controlla parametri
	if (!checkParams(pL, 1, 2, "soundvolume", false)) {
		lua_pushboolean(pL, false);
		return 1;
	}

	// verifica se la risorsa c'è !
	int numpars = lua_gettop(pL);
	int index=(int)lua_tonumber(pL, 1);
	if (index >= MAX_SOUNDS || !soundsInit[index]) {
		PFrogConsole::instance()->addconsole(0, "TRYING TO SOUNDVOLUME A SOUND NOT LOADED! %d", index);
		SendErrorIDE(0, "ERR||TRYING TO SOUNDVOLUME A SOUND NOT LOADED! %d", index);
		lua_pushboolean(pL, false);
		return 1;
	}

	if (numpars == 1) {
		// get
		lua_pushnumber(pL, 
			(soundsChannels[index] ? soundsChannels[index]->volume() : 0)
			);
		return 1;
	} else {
		// set
		if (soundsChannels[index])
			soundsChannels[index]->volume((int)lua_tonumber(pL, 2));
		return 0;
	}
}

// -- stopallsounds()
int Loader::lua_Function_StopAllSounds(lua_State *pL) {
	hss_speaker->stopSounds();

	lua_pushboolean(pL, true);
	return 1;
}

//-- stopallmusics()
int Loader::lua_Function_StopAllMusics(lua_State *pL) {
	hss_speaker->stopMusics();

	lua_pushboolean(pL, true);
	return 1;
}

#endif // #ifdef ENABLE_AUDIO

// --getnumiterations()
int Loader::lua_Function_Getnumiterations(lua_State *pL) {
	lua_pushnumber(pL, this->mainloopCount);
	return 1;
}

// --getfps()
int Loader::lua_Function_Getfps(lua_State *pL) {
	lua_pushnumber(pL, (int)GameFPS::instance()->GetLastFPS());
	return 1;
}

// --value=getmemorystatus(type)
int Loader::lua_Function_Getmemorystatus(lua_State *pL) {

	// controlla parametri
	if (!checkParams(pL, 1, "getmemorystatus", false)) {
		lua_pushboolean(pL, false);
		return 1;
	}

	MEMORYSTATUS memstatus;
	::GlobalMemoryStatus(&memstatus);

	int type = (int)lua_tonumber(pL, 1);
	double ret = 0.0;

	switch (type) {
		case 0:			ret = memstatus.dwTotalPhys;		break;
		case 1:			ret = memstatus.dwAvailPhys;		break;
		case 2:			ret = memstatus.dwTotalPageFile;	break;
		case 3:			ret = memstatus.dwAvailPageFile;	break;
		case 4:			ret = memstatus.dwTotalVirtual;		break;
		case 5:			ret = memstatus.dwAvailVirtual;		break;
		case 6:			ret = memstatus.dwMemoryLoad ;		break;
	}; // switch (type) {

	lua_pushnumber(pL, ret);
	return 1;
} // int Loader::lua_Function_Getmemorystatus(lua_State *pL) {

// --windowfocused()
int Loader::lua_Function_Windowfocused(lua_State *pL) {
	lua_pushboolean(pL, this->_appHasFocus);
	return 1;
}


// openconfig(ininame [,cryptkey])
int Loader::lua_Function_Openconfig(lua_State *pL) {

	// controlla parametri
	if (!checkParams(pL, 1, 2, "openconfig", false)) {
		lua_pushboolean(pL, false);
		return 1;
	}

	const char *ininame = (const char *)lua_tostring(pL, 1);

	// se vogliamo creare fba.ini, crealo nella dir corrente (non in userdata)
	bool want_create_fba_ini;
	char *inamelow=(char *)malloc(strlen(ininame)+1);
	strcpy(inamelow, ininame);
	for (unsigned int i=0; i < strlen(inamelow); i++) inamelow[i]=tolower(inamelow[i]);
	want_create_fba_ini=(strcmp(inamelow, "fba.ini") == 0);
	free(inamelow);

	// safe - chiudi e salva config precedente se era già aperto
	if (settings)
		settings->EndBufferedOperation();
	delete settings;


	if ( !want_create_fba_ini ) {
		// creo nella dir userdata
		// path dove creare il file
		TCHAR lpFileName[512],lpFileName2[512],lpDirOnly[512];

		// extract exe path
		GetModuleFileName(NULL, lpFileName, 255);

		// get the last backslash
		for (int i=_tcslen(lpFileName)-1; i>=0; i--) {
			if ( lpFileName[i] == _T('\\') ) {
				_stprintf(lpFileName2, _T("%.*s"), i+1, lpFileName); 
				break;
			}
		}
		
		// crea il nostro nome di file (con .fbaff alla fine)
		// Patch - 07 luglio 2008 - rimozione dir user_data
#if 0
		_stprintf(lpDirOnly, _T("%s%s"), lpFileName2, _T("userdata\\")); 
#else
		_stprintf(lpDirOnly, _T("%s"), lpFileName2); 
#endif
		// crea dir
		CreateDirectory(lpDirOnly, NULL);
	#ifdef ARM
		TCHAR finalfname[1024];
		MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, ininame, -1, finalfname, 1024);
		_stprintf(lpFileName, _T("%s%s.fbaff"), lpDirOnly, finalfname); 
	#else
		_stprintf(lpFileName, _T("%s%s.fbaff"), lpDirOnly, ininame); 
	#endif

		// crea oggetto settings
		settings=new GameSettings(lpFileName, false);
	
		// per gli ini diversi da fba.ini, accetto anche un eventuale chiave di crypt
		if ( lua_gettop(pL) == 2) {
			settings->SetCryptKey((unsigned char)lua_tonumber(pL, 2));
		}

	} else {
		// vogliamo creare fba.ini
		settings=new GameSettings(_T("fba.ini"), true);
	}

	settings->StartBufferedOperation();

	lua_pushboolean(pL, true);
	return 1;
}

// openconfigext(ininame [,cryptkey])
int Loader::lua_Function_OpenconfigExt(lua_State *pL) {

	// controlla parametri
	if (!checkParams(pL, 1, 2, "openconfigext", false)) {
		lua_pushboolean(pL, false);
		return 1;
	}

	const char *ininame = (const char *)lua_tostring(pL, 1);

	// safe - chiudi e salva config precedente se era già aperto
	if (settings)
		settings->EndBufferedOperation();
	delete settings;

	// path dove creare il file
	TCHAR lpFileName[512],lpFileName2[512];

	// extract exe path
	GetModuleFileName(NULL, lpFileName, 255);

	// get the last backslash
	for (int i=_tcslen(lpFileName)-1; i>=0; i--) {
		if ( lpFileName[i] == _T('\\') ) {
			_stprintf(lpFileName2, _T("%.*s"), i+1, lpFileName); 
			break;
		}
	}
	
#ifdef ARM
	TCHAR finalfname[1024];
	MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, ininame, -1, finalfname, 1024);
	_stprintf(lpFileName, _T("%s%s"), lpFileName2, finalfname); 
#else
	_stprintf(lpFileName, _T("%s%s"), lpFileName2, ininame); 
#endif

	// crea oggetto settings
	settings=new GameSettings(lpFileName, false);

	// eventuale chiave di crypt
	if ( lua_gettop(pL) == 2) {
		settings->SetCryptKey((unsigned char)lua_tonumber(pL, 2));
	}

	settings->StartBufferedOperation();

	lua_pushboolean(pL, true);
	return 1;
} //openconfigext

int Loader::lua_Function_Closeconfig(lua_State *pL) {

	// chiudi e distruggi oggetto config
	if (settings)
		settings->EndBufferedOperation();
	delete settings;
	settings=NULL;

	lua_pushboolean(pL, true);
	return 1;
}
// -- writeconfignumber(section, key, value)
int Loader::lua_Function_Writeconfignumber(lua_State *pL) {
	// controlla parametri
	if (!checkParams(pL, 3, "writeconfignumber", false)) {
		lua_pushboolean(pL, false);
		return 1;
	}

	// sanity
	if (!settings) {
		PFrogConsole::instance()->addconsole(0, "WRITECONFIGNUMBER: SETTINGS FILE NOT OPENED");
		SendErrorIDE(0, "ERR||WRITECONFIGNUMBER: SETTINGS FILE NOT OPENED");
		lua_pushboolean(pL, false);
		return 1;
	}

	const char *section = lua_tostring(pL, 1);
	const char *key = lua_tostring(pL, 2);
	long value = (long)lua_tonumber(pL, 3);

	settings->SaveLong((char *)section, (char *)key, value);	

	lua_pushboolean(pL, true);
	return 1;
}
int Loader::lua_Function_Writeconfigstring(lua_State *pL) {
	// controlla parametri
	if (!checkParams(pL, 3, "writeconfigstring", false)) {
		lua_pushboolean(pL, false);
		return 1;
	}

	// sanity
	if (!settings) {
		PFrogConsole::instance()->addconsole(0, "WRITECONFIGSTRING: SETTINGS FILE NOT OPENED");
		SendErrorIDE(0, "ERR||WRITECONFIGSTRING: SETTINGS FILE NOT OPENED");
		lua_pushboolean(pL, false);
		return 1;
	}

	const char *section = lua_tostring(pL, 1);
	const char *key = lua_tostring(pL, 2);
	const char *value = lua_tostring(pL, 3);

	settings->SaveShortString((char *)section, (char *)key, (char *)value);	

	lua_pushboolean(pL, true);
	return 1;
}

// -- readconfignumber(section, key [, default])
int Loader::lua_Function_Readconfignumber(lua_State *pL) {
	// controlla parametri
	if (!checkParams(pL, 2, 3, "readconfignumber", false)) {
		lua_pushboolean(pL, false);
		return 1;
	}

	// sanity
	if (!settings) {
		PFrogConsole::instance()->addconsole(0, "READCONFIGNUMBER: SETTINGS FILE NOT OPENED");
		SendErrorIDE(0, "ERR||READCONFIGNUMBER: SETTINGS FILE NOT OPENED");
		lua_pushboolean(pL, false);
		return 1;
	}

	const char *section = lua_tostring(pL, 1);
	const char *key = lua_tostring(pL, 2);
	int numpars = lua_gettop(pL);
	if (numpars == 2)
		lua_pushnumber(pL, 
			settings->LoadLong((char *)section, (char *)key, 0)
			);
	else
		lua_pushnumber(pL, 
			settings->LoadLong((char *)section, (char *)key, (int)lua_tonumber(pL, 3))
			);

	return 1;
} // -- readconfignumber(section, key [, default])

// -- readconfigstring(section, key [, default])
int Loader::lua_Function_Readconfigstring(lua_State *pL) {
	// controlla parametri
	if (!checkParams(pL, 2, 3, "readconfigstring", false)) {
		lua_pushboolean(pL, false);
		return 1;
	}

	// sanity
	if (!settings) {
		PFrogConsole::instance()->addconsole(0, "READCONFIGSTRING: SETTINGS FILE NOT OPENED");
		SendErrorIDE(0, "ERR||READCONFIGSTRING: SETTINGS FILE NOT OPENED");
		lua_pushboolean(pL, false);
		return 1;
	}

	const char *section = lua_tostring(pL, 1);
	const char *key = lua_tostring(pL, 2);	
	char *value = NULL;
	int numpars = lua_gettop(pL);

	if (numpars == 2) {
		value = settings->LoadShortString((char *)section, (char *)key, "");
	} else {
		const char *defvalue = lua_tostring(pL, 3);	
		value = settings->LoadShortString((char *)section, (char *)key, (char*)defvalue);
	}
	
	lua_pushstring(pL, value);
	free(value);

	return 1;
} // readconfigstring

// -- mousedown
int Loader::lua_Function_MouseDown(lua_State *pL) {
	lua_pushnumber(pL, _mouseIsDown);
	return 1;
} // mousedown


// -- mousex
int Loader::lua_Function_MouseX(lua_State *pL) {
	lua_pushnumber(pL, this->_lastClick.x);
	return 1;
}

// -- mousey
int Loader::lua_Function_MouseY(lua_State *pL) {
	lua_pushnumber(pL, this->_lastClick.y);
	return 1;
}

// -- mousein(x1,y1,x2,y2)
int Loader::lua_Function_MouseIn(lua_State *pL) {
	// controlla parametri
	if (!checkParams(pL, 4, "mousein", false)) return 0;
	
	int x1=(int)lua_tonumber(pL,1);
	int y1=(int)lua_tonumber(pL,2);
	int x2=(int)lua_tonumber(pL,3);
	int y2=(int)lua_tonumber(pL,4);

	if (this->_lastClick.y >= y1 && this->_lastClick.y <= y2 &&
		this->_lastClick.x >= x1 && this->_lastClick.x <= x2) 
		lua_pushboolean(pL, true);
	else
		lua_pushboolean(pL, false);
	return 1;
}

// -- keyleft(), right() etc
int Loader::lua_Function_NumKeypress(lua_State *pL) {

	// controlla parametri
	if (!checkParams(pL, 1, "numkeypress", false)) {
		lua_pushnumber(pL, 0);
		return 1;
	}

	int index = (int)lua_tonumber(pL, 1);

	if (index < MAX_KEYS_BUFFER)
		lua_pushnumber(pL, NUMKEYPRESS[index]);
	else
		lua_pushnumber(pL, 0);	// buffer key unavailable!

	return 1;
}
int Loader::lua_Function_KeyLeft(lua_State *pL) {
	lua_pushnumber(pL, keylist->vkLeft);
	return 1;
}
int Loader::lua_Function_KeyRight(lua_State *pL) {
	lua_pushnumber(pL, keylist->vkRight);
	return 1;
}
int Loader::lua_Function_KeyUp(lua_State *pL) {
	lua_pushnumber(pL, keylist->vkUp);
	return 1;
}
int Loader::lua_Function_KeyDown(lua_State *pL) {
	lua_pushnumber(pL, keylist->vkDown);
	return 1;
}
int Loader::lua_Function_KeyFire1(lua_State *pL) {
	lua_pushnumber(pL, keylist->vkA);
	return 1;
}
int Loader::lua_Function_KeyFire2(lua_State *pL) {
	lua_pushnumber(pL, keylist->vkB);
	return 1;
}
int Loader::lua_Function_KeyFire3(lua_State *pL) {
	lua_pushnumber(pL, keylist->vkC);
	return 1;
}

// -- getdate()
int Loader::lua_Function_GetDate(lua_State *pL)
{
	unsigned int i, toalloc=0;
	SYSTEMTIME st;
	::GetLocalTime( &st );

	// controlla parametri
	if (!checkParams(pL, 1, "getdate", false)) {
		lua_pushboolean(pL, false);
		return 1;
	}

	const char *format = lua_tostring(pL, 1);
	
	// conta quanti caratteri bisogna allocare espandendo la stringa
	for (i = 0; i < strlen(format); i++) {
		switch(format[i]) {
			case 'd':
			case 'w':
			case 'h':
			case 'm':
			case 'n':
			case 's':	
				toalloc+=2;		
			break;
			case 'u':
			case 'y':	
				toalloc+=4;		
			break;
			default:	
				++toalloc;
		}; // switch(format[i]) {
	} // for (i = 0; i < strlen(format); i++) {

	// compone la stringa finale
	char *final = (char *)malloc( toalloc + 1 );
	char *tmpfinal = (char *)malloc( toalloc + 1 );
	strcpy(final, "");
	strcpy(tmpfinal, "");

	for (i = 0; i < strlen(format); i++) {
		switch(format[i]) {
			case 'd':	sprintf(tmpfinal, "%s%d", final, st.wDay);	break;
			case 'w':	sprintf(tmpfinal, "%s%d", final, st.wDayOfWeek);	break;
			case 'h':	sprintf(tmpfinal, "%s%d", final, st.wHour);	break;
			case 'm':	sprintf(tmpfinal, "%s%d", final, st.wMonth);	break;
			case 'n':	sprintf(tmpfinal, "%s%d", final, st.wMinute);	break;
			case 's':	sprintf(tmpfinal, "%s%d", final, st.wSecond);	break;	
			case 'u':	sprintf(tmpfinal, "%s%d", final, st.wMilliseconds);	break;
			case 'y':	sprintf(tmpfinal, "%s%d", final, st.wYear);	break;
			default:	sprintf(tmpfinal, "%s%c", final, format[i]);	break;
		}; // switch(format[i]) {
		strcpy(final, tmpfinal);
	} // for (i = 0; i < strlen(format); i++) {

	// torna a LUA e libera memoria
	lua_pushstring(pL, final);
	free( final );
	free( tmpfinal );
	return 1;
} // int Loader::lua_Function_GetDate(lua_State *pL)

// -- getclock()
int Loader::lua_Function_GetClock(lua_State *pL)
{
	lua_pushnumber(pL, PocketPC::GetTickCount());
	return 1;
}

// -- include(filename)
int Loader::lua_Function_Include(lua_State *pL)
{
	// controlla parametri
	if (!checkParams(pL, 1, "include", false)) {
		lua_pushboolean(pL, false);
		return 1;
	}

	// estrai nome script da includere
	const char *_script = lua_tostring(pL, 1);

	// aggiungi .fba al nome dello script, se non c'è già
	char *finalfile=(char *)malloc(strlen(_script)+5);
	char *finalfileup=(char *)malloc(strlen(_script)+5);

	if ( !strstr(_script, ".fba") )
		sprintf(finalfile, "%s.fba", _script);
	else
		strcpy(finalfile, _script);
	strcpy(finalfileup, finalfile);

	// converti in maiuscolo
	for (unsigned int c=0; c < strlen(finalfileup); c++)
		finalfileup[c]=toupper(finalfileup[c]);


	////////////////
	// se è tra gli script da ignorare per l'include, ignoralo silenziosamente
	char *ignored=(char *)malloc(strlen(finalfileup)+8);
	sprintf(ignored, "||%s||", finalfileup);

	if (this->_ignoredIncludeVoidScripts && strstr(this->_ignoredIncludeVoidScripts, ignored)) {
		free(ignored);
		free(finalfile);
		free(finalfileup);

		lua_pushboolean(pL, true);
		return 1;
	}
	free(ignored);
	////////////////


#ifdef ARM
	TCHAR finaltext[1024];
	MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, finalfile, -1, finaltext, 1024);
#endif
	
	// prova a caricare lo script compresso
	bool loaded = true;

	LZArchive lza;
	LZItem lzi;

	// load and decompress the file
#ifdef ENABLE_SEPARATED_DAT_FOR_SCRIPTS
	if (lza.open(_T("fba.dats")) == false)
#else
	if (lza.open(_T("fba.dat")) == false)
#endif
		loaded=false;
#ifdef ARM
	else if (lza.read(finaltext, &lzi) == false)
#else
	else if (lza.read(finalfile, &lzi) == false)
#endif
		loaded=false;


	if ( !loaded ) {
		PFrogConsole::instance()->addconsole(0, "UNABLE TO INCLUDE %s", finalfile);
		SendErrorIDE(0, "ERR||UNABLE TO INCLUDE %s", finalfile);
	} else {
		// prova ad includere lo script
		lzi.decompress();
		unsigned char *buf = (unsigned char *)lzi.dBuffer();

		int scriptLoaded = luaL_loadbuffer (LUA,
								(const char *)buf ,
								lzi.dSize(),
								finalfileup) 
								||
								lua_pcall (LUA, 0, 0, 0) /* esegue lo script */;
		switch (scriptLoaded) {
			case 0:
				PFrogConsole::instance()->addconsole(0, "SCRIPT %s LOADED!", finalfile);
				SendErrorIDE(2, "INF||SCRIPT %s LOADED!", finalfile);
				lua_pushboolean(pL, true);
				break;
			case LUA_ERRSYNTAX:
			default:
				const char *error=lua_tostring (LUA, -1);
				PFrogConsole::instance()->addconsole(0, "SCRIPT %s NOT LOADED! %s" , finalfile, error);
				// in modalità debug, se c'è il socket, segnala errore anche sul socket
				SendErrorIDE(0,"ERR||SCRIPT %s NOT LOADED! %s", finalfile, error);
				lua_pushboolean(pL, false);
				break;
		};
	}

	free(finalfile);
	free(finalfileup);

	return 1;
}

// addconsole(testo)
int Loader::lua_Function_AddConsole(lua_State *pL)
{
	// controlla parametri
	if (!checkParams(pL, 1, "addconsole", true)) {
		lua_pushboolean(pL, false);
		return 1;
	}

	const char *text = lua_tostring(pL, 1);
	PFrogConsole::instance()->addconsole(0, (char *)text);

	lua_pushboolean(pL, true);
	return 1;
}

// debugsocket(testo)
int Loader::lua_Function_DebugSocket(lua_State *pL)
{
	// controlla parametri
#ifndef RELEASE_VERSION
	if (!checkParams(pL, 1, "debugsocket", false)) {
		lua_pushboolean(pL, false);
		return 1;
	}

	const char *text = lua_tostring(pL, 1);

	sprintf(tmpbuffer, "DBG||%s", text);
	dsock->socksend(0, tmpbuffer);

#endif
	lua_pushboolean(pL, true);
	return 1;
}

// clear(Red,green,blue)
int Loader::lua_Function_Clear(lua_State *pL)
{
	// controlla parametri
	if (!checkParams(pL, 3, "clear", true)) {
		lua_pushboolean(pL, false);
		return 1;
	}

	DISPLAY->Clear(Color((int)lua_tonumber(pL,1), (int)lua_tonumber(pL,2), (int)lua_tonumber(pL,3)));

	lua_pushboolean(pL, true);
	return 1;
}

// destroyimage(index)
int Loader::lua_Function_DestroyImage(lua_State *pL)
{
	// controlla parametri
	if (!checkParams(pL, 1, "destroyimage", false)) {
		lua_pushboolean(pL, false);
		return 1;
	}

	int index=(int)lua_tonumber(pL,1);

	// siamo negli indici consentiti
	if (index >= MAX_IMAGES) {
		PFrogConsole::instance()->addconsole(0, "DESTROYIMAGE: OUTBOUND IMAGE INDEX %d - MAX: %d", index, MAX_IMAGES);
		SendErrorIDE(0, "ERR||DESTROYIMAGE: OUTBOUND IMAGE INDEX %d - MAX: %d", index, MAX_IMAGES);
		lua_pushboolean(pL, false);
		return 1;
	}

	// distruggi l'immagine
	_FreeImage(index);

	lua_pushboolean(pL, true);
	return 1;
}

// -- print(x, y, text, red, green, blue)
int Loader::lua_Function_Print(lua_State *pL)
{
	// controlla parametri
	if (!checkParams(pL, 6, "print", true)) {
		lua_pushboolean(pL, false);
		return 1;
	}

	smalltext->drawstring(DISPLAY, 
		Color((int)lua_tonumber(pL, 4), (int)lua_tonumber(pL, 5), (int)lua_tonumber(pL, 6)), 
		(int)lua_tonumber(pL, 1),(int)lua_tonumber(pL, 2),
		(char *)lua_tostring(pL, 3));

	lua_pushboolean(pL, true);
	return 1;
}


// -- fillcircle(x, y, radius, red, green, blue)
// -- circle(x, y, radius, red, green, blue)
int Loader::lua_Function_Circle(lua_State *pL, bool filled)
{
	// controlla parametri
	if (!checkParams(pL, 6, "circle", true)) {
		lua_pushboolean(pL, false);
		return 1;
	}

	if (!filled) {
		DISPLAY->DrawCircle(
			(int)lua_tonumber(pL,1),(int)lua_tonumber(pL,2),
			(int)lua_tonumber(pL,3),
			Color((int)lua_tonumber(pL,4), (int)lua_tonumber(pL,5), (int)lua_tonumber(pL,6)));
	} else {
		// filled circle
		double dy;
		double r2=((int)lua_tonumber(pL,3))*((int)lua_tonumber(pL,3));
		int xmdx, xmdy, xpdx, xpdy;
		int ymdx, ymdy, ypdx, ypdy, e;
		int x = (int)lua_tonumber(pL,1), y = (int)lua_tonumber(pL,2);
		double et= ((int)lua_tonumber(pL,3)) * sqrt(2.0) / 2.0;
		
		if (et-(int)et > .5)
			e=(int)(et+1);
		else
			e=(int)(et);

		for (int dx=0; dx <= e; dx ++) {
			
			dy = sqrt((double)(r2 - dx*dx)); 
			xmdx=(int)(x-dx); xmdy=(int)(x-dy);
			xpdx=(int)(x+dx); xpdy=(int)(x+dy);
			ypdx=(int)(y+dx); ymdx=(int)(y-dx);
			ymdy=(int)(y-dy); ypdy=(int)(y+dy);

			//DISPLAY->DrawHLine(LeftX, TopBotY, (RightX-LeftX)
			_DrawHorizLine(DISPLAY, xmdx, xpdx, ypdy, Color((int)lua_tonumber(pL,4), (int)lua_tonumber(pL,5), (int)lua_tonumber(pL,6))); 
			_DrawHorizLine(DISPLAY, xmdx, xpdx, ymdy, Color((int)lua_tonumber(pL,4), (int)lua_tonumber(pL,5), (int)lua_tonumber(pL,6))); 
			_DrawHorizLine(DISPLAY, xmdy, xpdy, ypdx, Color((int)lua_tonumber(pL,4), (int)lua_tonumber(pL,5), (int)lua_tonumber(pL,6))); 
			_DrawHorizLine(DISPLAY, xmdy, xpdy, ymdx, Color((int)lua_tonumber(pL,4), (int)lua_tonumber(pL,5), (int)lua_tonumber(pL,6))); 

		} // for (int dx=0; dx < e; dx ++) 
	} // filledcircle

	lua_pushboolean(pL, true);
	return 1;
} // lua_Function_Circle

// disegna una linea orizzontale
void Loader::_DrawHorizLine(Display *display, int LeftX, int RightX, int TopBotY, Pixel forecolor) { display->DrawHLine(LeftX, TopBotY, (RightX-LeftX), forecolor); }

// rect(x1,y1,x2,y2,red,green,blue)
// fillrect(x1,y1,x2,y2,red,green,blue)
int Loader::lua_Function_Rect(lua_State *pL, bool filled)
{
	// controlla parametri
	if (!checkParams(pL, 7, "rect", true)) {
		lua_pushboolean(pL, false);
		return 1;
	}

	if (!filled) 
		DISPLAY->DrawRect(
			(int)lua_tonumber(pL,1), (int)lua_tonumber(pL,2),
			(int)lua_tonumber(pL,3), (int)lua_tonumber(pL,4),
			Color((int)lua_tonumber(pL,5),(int)lua_tonumber(pL,6),(int)lua_tonumber(pL,7))
			);
	else
		DISPLAY->FillRect(
			(int)lua_tonumber(pL,1), (int)lua_tonumber(pL,2),
			(int)lua_tonumber(pL,3), (int)lua_tonumber(pL,4),
			Color((int)lua_tonumber(pL,5),(int)lua_tonumber(pL,6),(int)lua_tonumber(pL,7))
			);
		
	lua_pushboolean(pL, true);
	return 1;
}

// line(x1, y1, x2, y2, red, green, blue)
int Loader::lua_Function_Line(lua_State *pL)
{
	// controlla parametri
	if (!checkParams(pL, 7, "line", true)) {
		lua_pushboolean(pL, false);
		return 1;
	}

	DISPLAY->DrawLine(
		(int)lua_tonumber(pL,1), (int)lua_tonumber(pL,2),
		(int)lua_tonumber(pL,3), (int)lua_tonumber(pL,4),
		Color((int)lua_tonumber(pL,5),(int)lua_tonumber(pL,6),(int)lua_tonumber(pL,7))
		);

	lua_pushboolean(pL, true);
	return 1;
} // line


// -- fillpoly(red, green, blue [,px, py][,px, py][,px, py]....)
// -- poly(red, green, blue [,px, py][,px, py][,px, py]....)
int Loader::lua_Function_Poly(lua_State *pL, bool filled)
{
	// poly è una funzione particolare poichè può accettare infiniti parametri, ma 
	// comunque piu' o uguale a 6 e multiplo di 3
	int numpars = lua_gettop(pL);
#ifndef RELEASE_VERSION

	if (!DISPLAY) {
		PFrogConsole::instance()->addconsole(0, "POLY CALLED BUT DISPLAY NOT AVAILABLE YET!");
		SendErrorIDE(0, "ERR||POLY CALLED BUT DISPLAY NOT AVAILABLE YET!");
		return false;
	}
	if ((numpars < 6) || ( (numpars-3) % 2 != 0)) {
		PFrogConsole::instance()->addconsole(0, "POLY WRONG # OF PARAM %d", 
			numpars);
		SendErrorIDE(0, "ERR||POLY WRONG # OF PARAM %d", 
			numpars);
		return false;
	}
#endif
	int red = (int)lua_tonumber(pL, 1);
	int green = (int)lua_tonumber(pL, 2);
	int blue = (int)lua_tonumber(pL, 3);
	int numpoints=(int)((numpars-3) / 2);
	int a,c=4;

	Point *point=(Point *)malloc(sizeof(Point)*numpoints);
	for (a=0; a < numpoints; a++) {
		point[a].x=(int)lua_tonumber(pL, c++);
		point[a].y=(int)lua_tonumber(pL, c++);
	}

	if (filled)
		DISPLAY->FillPoly(point, numpoints, Color(red, green,blue));
	else
		DISPLAY->DrawPoly(point, numpoints, Color(red, green,blue));

	free(point);

	lua_pushboolean(pL, true);
	return 1;
} // poly

// point(x, y, [red, green, blue])
int Loader::lua_Function_Point(lua_State *pL)
{
	// controlla parametri
	if (!checkParams(pL, /* 2, */ 5, "point", true)) {
		lua_pushboolean(pL, false);
		return 1;
	}

	int numpars = lua_gettop(pL);

	//if (numpars == 5) {

		DISPLAY->SetPixel((int)lua_tonumber(pL,1), (int)lua_tonumber(pL,2),
			Color((int)lua_tonumber(pL,3), (int)lua_tonumber(pL,4),
			(int)lua_tonumber(pL,5)));

		lua_pushboolean(pL, true);
		return 1;

	/*
	} else {

		Pixel color=DISPLAY->GetPixel((int)lua_tonumber(pL,1), (int)lua_tonumber(pL,2));

		lua_pushnumber(pL, 1);
		lua_pushnumber(pL, 2);
		lua_pushnumber(pL, 3);
		return 3;
	}
	*/
} // point

// -- blending([newvalue])
int Loader::lua_Function_Blending(lua_State *pL)
{
	// controlla parametri
	if (!checkParams(pL, 0, 1, "blending", true)) {
		lua_pushboolean(pL, false);
		return 1;
	}

	int numpars = lua_gettop(pL);

	if (numpars == 0)
		lua_pushnumber(pL, this->_currentBlending);
	else {
		unsigned char blend = (unsigned char)lua_tonumber(pL, 1);
		this->_currentBlending=blend;
		DISPLAY->SetBlending(this->_currentBlending);
		lua_pushboolean(pL, true);
	}

	return 1;
} // blending


// getcolor(reg, green, blue)
int Loader::lua_Function_GetColor(lua_State *pL)
{
	// controlla parametri
	if (!checkParams(pL, 3, "getcolor", false)) {
		lua_pushboolean(pL, false);
		return 1;
	}
	
	lua_pushnumber(pL, Color(
			(int)lua_tonumber(pL, 1),
			(int)lua_tonumber(pL, 2),
			(int)lua_tonumber(pL, 3)
		));
	return 1;
} // getcolor

// clipping([x1,y1,x2,y2])
int Loader::lua_Function_Clipping(lua_State *pL)
{
	// controlla parametri
	if (!checkParams(pL, 0, 4, "clipping", true)) {
		lua_pushboolean(pL, false);
		return 1;
	}

	int numpars = lua_gettop(pL);

	if (numpars == 0) {
		Rect clip = DISPLAY->GetClipping();
		lua_pushnumber(pL, clip.left);
		lua_pushnumber(pL, clip.top);
		lua_pushnumber(pL, clip.right);
		lua_pushnumber(pL, clip.bottom);
		return 4;
	} else {
		DISPLAY->SetClipping(Rect(
				(int)lua_tonumber(pL, 1),
				(int)lua_tonumber(pL, 2),
				(int)lua_tonumber(pL, 3),
				(int)lua_tonumber(pL, 4)
			));
		lua_pushboolean(pL, true);
		return 1;
	}

} // clipping

// imagecolor(slot, x, y [red, green, blue])
int Loader::lua_Function_ImageColor(lua_State *pL)
{
	// controlla parametri
	if (!checkParams(pL, 3, 6, "imagecolor", true)) {
		lua_pushboolean(pL, false);
		return 1;
	}

	int numpars = lua_gettop(pL);
	int index = (int)lua_tonumber(pL, 1);

	// controlla indici
	if (index >= MAX_IMAGES || !imagesInit[index]) {
		PFrogConsole::instance()->addconsole(0, "IMAGECOLOR: IMAGE INDEX NOT LOADED %d", index);
		SendErrorIDE(0, "ERR|IMAGECOLOR: IMAGE INDEX NOT LOADED %d", index);

		lua_pushnumber(pL, 0);
		return 1;
	}

	int x = (int)lua_tonumber(pL, 2);
	int y = (int)lua_tonumber(pL, 3);
	int w = (int)images[index]->GetWidth();

	Surface::LockInfo lock;
	images[index]->Lock(lock);

	if (numpars == 3)
		lua_pushnumber(pL, lock.pixels[w*y+x]);
	else {
		lock.pixels[w*y+x]=Color(
				(int)lua_tonumber(pL, 4),
				(int)lua_tonumber(pL, 5),
				(int)lua_tonumber(pL, 6)
			);
		lua_pushboolean(pL, true);
	}
	images[index]->Unlock();

	return 1;
} // imagecolor

// imageheight(index)
int Loader::lua_Function_ImageHeight(lua_State *pL)
{
	// controlla parametri
	if (!checkParams(pL, 1, "imageheight", false)) {
		lua_pushboolean(pL, false);
		return 1;
	}

	int index=(int)lua_tonumber(pL, 1);

	if (index >= MAX_IMAGES || !imagesInit[index]) {
		PFrogConsole::instance()->addconsole(0, "IMAGEHEIGHT: IMAGE INDEX NOT LOADED %d", index);
		SendErrorIDE(0, "ERR|IMAGEHEIGHT: IMAGE INDEX NOT LOADED %d", index);

		lua_pushnumber(pL, 0);
		return 1;
	}

	lua_pushnumber(pL, images[index]->GetHeight());
	return 1;
} // image height


// imagewidth(index)
int Loader::lua_Function_ImageWidth(lua_State *pL)
{
	// controlla parametri
	if (!checkParams(pL, 1, "imagewidth", false)) {
		lua_pushboolean(pL, false);
		return 1;
	}

	int index=(int)lua_tonumber(pL, 1);

	if (index >= MAX_IMAGES || !imagesInit[index]) {
		PFrogConsole::instance()->addconsole(0, "IMAGEWIDTH: IMAGE INDEX NOT LOADED %d", index);
		SendErrorIDE(0, "ERR||IMAGEWIDTH: IMAGE INDEX NOT LOADED %d", index);

		lua_pushnumber(pL, 0);
		return 1;
	}

	lua_pushnumber(pL, images[index]->GetWidth());
	return 1;
} // image width

// rendertarget([index])
int Loader::lua_Function_RenderTarget(lua_State *pL)
{
	// controlla parametri
	if (!checkParams(pL, 0, 1, "rendertarget", false)) {
		lua_pushboolean(pL, false);
		return 1;
	}

	int numpars = lua_gettop(pL);

	if (numpars == 0) {
		DISPLAY->SetRenderTarget(0);
		lua_pushboolean(pL, true);
		return 1;
	} else {
		// verifica se la risorsa c'è !
		int index=(int)lua_tonumber(pL, 1);
		if (index >= MAX_IMAGES || !imagesInit[index]) {
			PFrogConsole::instance()->addconsole(0, "TRYING SET RENDER TARGET %d", index);
			SendErrorIDE(0, "ERR||TRYING SET RENDER TARGET %d", index);
			lua_pushboolean(pL, false);
			return 1;
		}
		//
		DISPLAY->SetRenderTarget(images[index]);
		lua_pushboolean(pL, true);
		return 1;
	}

} // rendertarget

// loadimage([index,] picname)
int Loader::lua_Function_LoadImage(lua_State *pL)
{
	// controlla parametri
	if (!checkParams(pL, 1, 2, "loadimage", false)) {
		lua_pushboolean(pL, false);
		return 1;
	}

	// verifica se dobbiamo allocare nuove surfaces nell'array
	int numpars = lua_gettop(pL);
	int index;
	const char *image;

	// se abbiamo passato solo un parametro, vogliamo l'autoassegnazione di uno slot
	// quindi cerco uno slot libero
	if (numpars == 1) {
		// Cerca il primo slot libero e per default lasciamo uno slot fuori limite
		index = MAX_IMAGES;
		for (int s=0; s < MAX_IMAGES; s++) {
			if (!imagesInit[s]) { index=s; break; }
		}
		image = lua_tostring(pL, 1);
	} else {
		index=(int)lua_tonumber(pL, 1);
		image = lua_tostring(pL, 2);
	}

	// siamo negli indici consentiti
	if (index >= MAX_IMAGES) {
		PFrogConsole::instance()->addconsole(0, "LOADIMAGE: OUTBOUND IMAGE INDEX %d - MAX: %d", index, MAX_IMAGES);
		SendErrorIDE(0, "ERR|LOADIMAGE: OUTBOUND IMAGE INDEX %d - MAX: %d", index, MAX_IMAGES);
		lua_pushboolean(pL, false);
		return 1;
	}

	// aggiungi .img al nome della pic
	char *finalfile=(char *)malloc(strlen(image)+5);

	// piccolo trick, se l'utente passa .png o .jpg, trasformiamo in .img per via del compressore...
	if (
		strlen(image) > 3 && 
		 (
			(
			tolower(image[strlen(image)-4])=='.' && tolower(image[strlen(image)-3])=='p' && 
			tolower(image[strlen(image)-2])=='n' && tolower(image[strlen(image)-1])=='g'
			) || (
			tolower(image[strlen(image)-4])=='.' && tolower(image[strlen(image)-3])=='j' && 
			tolower(image[strlen(image)-2])=='p' && tolower(image[strlen(image)-1])=='g'
			)
		  )
		) {
			strcpy(finalfile, image);
			finalfile[strlen(image)-3]='\0';	// tronca png o jpg
			strcat(finalfile, "img");
	}
	else if (strlen(image) > 3 && tolower(image[strlen(image)-4])=='.' && tolower(image[strlen(image)-3])=='i' && 
		tolower(image[strlen(image)-2])=='m' && tolower(image[strlen(image)-1])=='g')
			// .img
			sprintf(finalfile, "%s", image);
	else
			// altri (aggiunge img)
			sprintf(finalfile, "%s.img", image);

	//sprintf(finalfile, "%s.img", image);
#ifdef ARM
	TCHAR finaltext[1024];
	MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, finalfile, -1, finaltext, 1024);
#endif
	
	// verifica se dobbiamo allocare nuove surfaces
	if (index+1 > maxAllocatedImages) {
		PFrogConsole::instance()->addconsole(0, "REALLOCATE SURFACES FROM %d TO %d", maxAllocatedImages, index+1);
		SendErrorIDE(3, "INF||REALLOCATE SURFACES FROM %d TO %d", maxAllocatedImages, index+1);
		maxAllocatedImages=index+1;
		images=(Surface **)realloc(images, sizeof(Surface *)*maxAllocatedImages);
	}

	// se l'immagine era già allocata, distruggila
	_FreeImage(index);

	// Carica l'immagine nell'index specificato
#ifdef ARM
	images[index]=LoadImage(_T("fba.dat"), finaltext);
#else
	images[index]=LoadImage(_T("fba.dat"), finalfile);
#endif
	if (images[index]) {
		images[index]->SetColorMask(this->transColor);
		PFrogConsole::instance()->addconsole(0, "LOADED IMAGE %d - %s", index, finalfile);
		SendErrorIDE(3, "INF||LOADED IMAGE %d - %s", index, finalfile);
		imagesInit[index]=true;
		lua_pushnumber(pL, index);
	} else {
		PFrogConsole::instance()->addconsole(0, "CANNOT LOAD IMAGE %d", index);
		SendErrorIDE(0, "ERR||CANNOT LOAD IMAGE %d", index);
		imagesInit[index]=false;
		lua_pushboolean(pL, false);
	}

	free(finalfile);

	return 1;
} // loadimage



// -- createimage([slot,] width, height)
int Loader::lua_Function_CreateImage(lua_State *pL)
{
	// controlla parametri
	if (!checkParams(pL, 2, 3, "createimage", false)) {
		lua_pushboolean(pL, false);
		return 1;
	}

	// verifica se dobbiamo allocare nuove surfaces nell'array
	int numpars = lua_gettop(pL);
	int index, width, height;

	// se abbiamo passato solo due parametri, vogliamo l'autoassegnazione di uno slot
	// quindi cerco uno slot libero
	if (numpars == 2) {
		// Cerca il primo slot libero e per default lasciamo uno slot fuori limite
		index = MAX_IMAGES;
		for (int s=0; s < MAX_IMAGES; s++) {
			if (!imagesInit[s]) { index=s; break; }
		}
		width = (int)lua_tonumber(pL, 1);
		height = (int)lua_tonumber(pL, 2);
	} else {
		index=(int)lua_tonumber(pL, 1);
		width = (int)lua_tonumber(pL, 2);
		height = (int)lua_tonumber(pL, 3);
	}

	// siamo negli indici consentiti
	if (index >= MAX_IMAGES) {
		PFrogConsole::instance()->addconsole(0, "CREATEIMAGE: OUTBOUND IMAGE INDEX %d - MAX: %d", index, MAX_IMAGES);
		SendErrorIDE(0, "ERR|CREATEIMAGE: OUTBOUND IMAGE INDEX %d - MAX: %d", index, MAX_IMAGES);
		lua_pushboolean(pL, false);
		return 1;
	}
	
	// verifica se dobbiamo allocare nuove surfaces
	if (index+1 > maxAllocatedImages) {
		PFrogConsole::instance()->addconsole(0, "REALLOCATE SURFACES FROM %d TO %d", maxAllocatedImages, index+1);
		SendErrorIDE(3, "INF||REALLOCATE SURFACES FROM %d TO %d", maxAllocatedImages, index+1);
		maxAllocatedImages=index+1;
		images=(Surface **)realloc(images, sizeof(Surface *)*maxAllocatedImages);
	}

	// se l'immagine era già allocata, distruggila
	_FreeImage(index);

	// crea l'immagine
	if (width > 0 && height > 0)
		images[index]=DISPLAY->CreateSurface(width, height);

	if (!images[index]) {
		PFrogConsole::instance()->addconsole(0, "UNABLE TO CREATE IMAGES %d - %d", maxAllocatedImages, index);
		SendErrorIDE(0, "ERR||UNABLE TO CREATE IMAGES %d - %d", maxAllocatedImages, index);
		imagesInit[index]=false;
	} else {
		// riempi con il colore di trasparenza per default
		Surface *oldtarget=DISPLAY->SetRenderTarget(images[index]);
		DISPLAY->Clear(this->transColor);
		DISPLAY->SetRenderTarget(oldtarget);

		images[index]->SetColorMask(this->transColor);
		imagesInit[index]=true;
	}

	lua_pushnumber(pL, index);
	return 1;
} // createimage

//-- drawimage(index, sx, sy)
//-- drawimage(index, sx, sy, cx1, cy1, cx2, cy2)
int Loader::lua_Function_DrawImage(lua_State *pL)
{
	// controlla parametri
	if (!checkParams(pL, 3, 7, "drawimage", true)) {
		lua_pushboolean(pL, false);
		return 1;
	}

	// verifica se la risorsa c'è !
	int index=(int)lua_tonumber(pL, 1);
	if (index >= MAX_IMAGES || !imagesInit[index]) {
		PFrogConsole::instance()->addconsole(0, "TRYING TO DRAW AN IMAGE NOT LOADED! %d", index);
		SendErrorIDE(0, "ERR||TRYING TO DRAW AN IMAGE NOT LOADED! %d", index);
		lua_pushboolean(pL, false);
		return 1;
	}

	// ora procedi col disegno..
	int numpars = lua_gettop(pL);

	switch (numpars) {
		//-- drawimage(index, sx, sy, cx1, cy1, cx2, cy2)
		case 7:
			DISPLAY->Blit(
				(int)lua_tonumber(pL, 2),
				(int)lua_tonumber(pL, 3),
				images[index],
					&Rect(
						(int)lua_tonumber(pL, 4),
						(int)lua_tonumber(pL, 5),
						(int)lua_tonumber(pL, 6),
						(int)lua_tonumber(pL, 7)
					)
				);
		break;
		//-- drawimage(index, sx, sy)
		case 3:
			DISPLAY->Blit(
				(int)lua_tonumber(pL, 2),
				(int)lua_tonumber(pL, 3),
				images[index]
				);
		break;
	};

	lua_pushboolean(pL, true);
	
	return 1;
} // drawimage


//-- drawstretchimage(index, sx1, sy1, sx2, sy2, dx1, dy1, dx2, dy2)
int Loader::lua_Function_DrawStretchImage(lua_State *pL)
{
	// controlla parametri
	if (!checkParams(pL, 9, "drawstretchimage", true)) {
		lua_pushboolean(pL, false);
		return 1;
	}

	// verifica se la risorsa c'è !
	int index=(int)lua_tonumber(pL, 1);
	if (index >= MAX_IMAGES || !imagesInit[index]) {
		PFrogConsole::instance()->addconsole(0, "TRYING TO DRAW AN IMAGE NOT LOADED! %d", index);
		SendErrorIDE(0, "ERR||TRYING TO DRAW AN IMAGE NOT LOADED! %d", index);
		lua_pushboolean(pL, false);
		return 1;
	}

	int sx1=(int)lua_tonumber(pL, 2);
	int sy1=(int)lua_tonumber(pL, 3);
	int sx2=(int)lua_tonumber(pL, 4);
	int sy2=(int)lua_tonumber(pL, 5);
	int dx1=(int)lua_tonumber(pL, 6);
	int dy1=(int)lua_tonumber(pL, 7);
	int dx2=(int)lua_tonumber(pL, 8);
	int dy2=(int)lua_tonumber(pL, 9);
	
	DISPLAY->BlitStretch(Rect(dx1, dy1, dx2, dy2), images[index],
		&Rect(sx1, sy1, sx2, sy2));

	lua_pushboolean(pL, true);
	return 1;
} // drawstretchimage


//-- drawrotateimage(index, x,y, angle)
int Loader::lua_Function_DrawRotateImage(lua_State *pL)
{
	// controlla parametri
	if (!checkParams(pL, 4, "drawrotateimage", true)) {
		lua_pushboolean(pL, false);
		return 1;
	}

	// verifica se la risorsa c'è !
	int index=(int)lua_tonumber(pL, 1);
	if (index >= MAX_IMAGES || !imagesInit[index]) {
		PFrogConsole::instance()->addconsole(0, "TRYING TO DRAW AN IMAGE NOT LOADED! %d", index);
		SendErrorIDE(0, "ERR||TRYING TO DRAW AN IMAGE NOT LOADED! %d", index);
		lua_pushboolean(pL, false);
		return 1;
	}

	int x=(int)lua_tonumber(pL, 2);
	int y=(int)lua_tonumber(pL, 3);
	int angle=(int)lua_tonumber(pL, 4);

	DISPLAY->BlitRotated(x, y, GRADE[angle], images[index]);

	lua_pushboolean(pL, true);
	return 1;
} // drawrotateimage

//-- drawrotatestretchimage(indexsource, indexdest, destx, desty, angle, sx1, sy1, sx2, sy2)
int Loader::lua_Function_DrawRotateStretchImage(lua_State *pL)
{
	// controlla parametri
	if (!checkParams(pL, 9, "drawrotatestretchimage", true)) {
		lua_pushboolean(pL, false);
		return 1;
	}

	// verifica se la risorsa c'è !
	int indexsource=(int)lua_tonumber(pL, 1);
	int indexdest=(int)lua_tonumber(pL, 2);
	if (indexsource >= MAX_IMAGES || !imagesInit[indexsource]) {
		PFrogConsole::instance()->addconsole(0, "TRYING TO DRAW AN IMAGE NOT LOADED! %d", indexsource);
		SendErrorIDE(0, "ERR||TRYING TO DRAW AN IMAGE NOT LOADED! %d", indexsource);
		lua_pushboolean(pL, false);
		return 1;
	}
	if (indexdest >= MAX_IMAGES || !imagesInit[indexdest]) {
		PFrogConsole::instance()->addconsole(0, "TRYING TO DRAW AN IMAGE NOT LOADED! %d", indexdest);
		SendErrorIDE(0, "ERR||TRYING TO DRAW AN IMAGE NOT LOADED! %d", indexdest);
		lua_pushboolean(pL, false);
		return 1;
	}

	int destx = (int)lua_tonumber(pL, 3);
	int desty = (int)lua_tonumber(pL, 4);
	int angle = (int)lua_tonumber(pL, 5);
	int sx1 = (int)lua_tonumber(pL, 6);
	int sy1 = (int)lua_tonumber(pL, 7);
	int sx2 = (int)lua_tonumber(pL, 8);
	int sy2 = (int)lua_tonumber(pL, 9);

	DISPLAY->BlitRotatedStretch(destx, desty, GRADE[angle], 
		images[indexsource], images[indexdest], 
		&Rect(sx1, sy1, sx2, sy2));

	lua_pushboolean(pL, true);
	return 1;
} // drawrotatestretchimage

//-- colormask(index, red, green, blue)
int Loader::lua_Function_ColorMask(lua_State *pL)
{
	// controlla parametri
	if (!checkParams(pL, 4, "colormask", false)) {
		lua_pushboolean(pL, false);
		return 1;
	}

	// controlla index immagine
	int index=(int)lua_tonumber(pL, 1);

	if (index >= MAX_IMAGES || !imagesInit[index]) {
		PFrogConsole::instance()->addconsole(0, "TRYING TO COLORMASK AN IMAGE NOT LOADED! %d", index);
		SendErrorIDE(0, "ERR||TRYING TO COLORMASK AN IMAGE NOT LOADED! %d", index);
		lua_pushboolean(pL, false);
		return 1;
	}

	/*
	int numpars = lua_gettop(pL);
	
	if (numpars == 1) {
		int mask=images[index]->GetColorMask();

		lua_pushnumber(pL, (int)((mask & 0xF800) >> 11)<<3);		
		lua_pushnumber(pL, (int)((mask & 0x7E0) >> 5)<<2);		
		lua_pushnumber(pL, (int)((mask & 0x1F))<<3);		
		return 3;
	} else {
	*/
		images[index]->SetColorMask(
			Color((int)lua_tonumber(pL, 2),
			(int)lua_tonumber(pL, 3),
			(int)lua_tonumber(pL, 4)));

		lua_pushboolean(pL, true);
		return 1;
	//}

} // colormask


// loadlibrary([index,] filename)
int Loader::lua_Function_LoadLibrary(lua_State *pL)
{
	// controlla parametri
	if (!checkParams(pL, 1, 2, "loadlibrary", false)) {
		lua_pushboolean(pL, false);
		return 1;
	}

	// verifica se dobbiamo allocare nuove libraries nell'array
	int numpars = lua_gettop(pL);
	int index;
	const char *library;

	// se abbiamo passato solo un parametro, vogliamo l'autoassegnazione di uno slot
	// quindi cerco uno slot libero
	if (numpars == 1) {
		// Cerca il primo slot libero e per default lasciamo uno slot fuori limite
		index = MAX_LIBS;
		for (int s=0; s < MAX_LIBS; s++) {
			if (!libsInit[s]) { index=s; break; }
		}
		library = lua_tostring(pL, 1);
	} else {
		index=(int)lua_tonumber(pL, 1);
		library = lua_tostring(pL, 2);
	}

	// siamo negli indici consentiti
	if (index >= MAX_LIBS) {
		PFrogConsole::instance()->addconsole(0, "LOADLIBRARY: OUTBOUND LIBRARY INDEX %d - MAX: %d", index, MAX_LIBS);
		SendErrorIDE(0, "ERR|LOADLIBRARY: OUTBOUND LIBRARY INDEX %d - MAX: %d", index, MAX_LIBS);
		lua_pushboolean(pL, false);
		return 1;
	}


#ifdef ARM
	TCHAR finaltext[1024];
	MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, library, -1, finaltext, 1024);
#endif
	
	// verifica se dobbiamo allocare nuove libraries
	if (index+1 > maxAllocatedLibs) {
		PFrogConsole::instance()->addconsole(0, "REALLOCATE LIBS FROM %d TO %d", maxAllocatedLibs, index+1);
		SendErrorIDE(3, "INF||REALLOCATE LIBS FROM %d TO %d", maxAllocatedLibs, index+1);
		maxAllocatedLibs=index+1;
		libs=(HINSTANCE *)realloc(libs, sizeof(HINSTANCE)*maxAllocatedLibs);
	}

	// se la libreria era già caricata, liberala ora
	if (libsInit[index]) {
		// call library destroy
		typedef void (*_ExecLib) (void); 
		_ExecLib dllfunc = (_ExecLib)GetProcAddress(libs[index], _T("FBA_freelibrary"));
		if (dllfunc) dllfunc();
		PFrogConsole::instance()->addconsole(0, "LIBRARY %d DESTROYED", index);
		// free dll
		FreeLibrary(libs[index]);
		libsInit[index]=false;
	}

	// recupera full path corrente della library specificata
	// path dove cercare il file
	TCHAR lpFileName[512],lpFileName2[512];

	// extract exe path
	GetModuleFileName(NULL, lpFileName, 255);

	// get the last backslash
	for (int i=_tcslen(lpFileName)-1; i>=0; i--) {
		if ( lpFileName[i] == _T('\\') ) {
			_stprintf(lpFileName2, _T("%.*s"), i+1, lpFileName); 
			break;
		}
	}
	
#ifdef ARM
	TCHAR finalfname[1024];
	MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, library, -1, finalfname, 1024);
	_stprintf(lpFileName, _T("%sarm_%s"), lpFileName2, finalfname); 
#else
	_stprintf(lpFileName, _T("%sx86_%s"), lpFileName2, library); 
#endif

	// prova a caricare la library!
	libs[index] = LoadLibrary(lpFileName);

	// in caso di errore, segnala e considera la lib non caricata
	if ( !libs[index] ) {
		libsInit[index] = false;
		PFrogConsole::instance()->addconsole(0, "CANNOT LOAD LIB %d - %s", index, library);
		SendErrorIDE(0, "ERR||CANNOT LOAD LIB %d - %s", index, library);
		libsInit[index]=false;
		lua_pushboolean(pL, false);
	} else {

		// chiama funzione init dalla .dll
		typedef void (*_ExecLib) (void); 
		_ExecLib dllfunc = (_ExecLib)GetProcAddress(libs[index], _T("FBA_initlibrary"));
		if (dllfunc) {
			
			dllfunc();

			libsInit[index] = true;
			PFrogConsole::instance()->addconsole(0, "LOADED LIB %d - %s", index, library);
			SendErrorIDE(3, "INF||LOADED LIB %d - %s", index, library);
			lua_pushnumber(pL, index);
		} else {
			libsInit[index] = false;
			PFrogConsole::instance()->addconsole(0, "CANNOT CALL INIT LIB %d - %s", index, library);
			SendErrorIDE(0, "ERR||CANNOT CALL INIT LIB %d - %s", index, library);
			libsInit[index]=false;
			lua_pushboolean(pL, false);
		}
		//
	}

	return 1;
} // lua_Function_LoadLibrary



// freelibrary(index)
int Loader::lua_Function_FreeLibrary(lua_State *pL)
{
	// controlla parametri
	if (!checkParams(pL, 1, "freelibrary", false)) {
		lua_pushboolean(pL, false);
		return 1;
	}

	int index=(int)lua_tonumber(pL,1);

	// siamo negli indici consentiti
	if (index >= MAX_LIBS) {
		PFrogConsole::instance()->addconsole(0, "FREELIBRARY: OUTBOUND LIB INDEX %d - MAX: %d", index, MAX_LIBS);
		SendErrorIDE(0, "ERR||FREELIBRARY: OUTBOUND LIB INDEX %d - MAX: %d", index, MAX_LIBS);
		lua_pushboolean(pL, false);
		return 1;
	}

	// distruggi la library, se caricata
	if (libsInit[index]) {
		// call library destroy
		typedef void (*_ExecLib) (void); 
		_ExecLib dllfunc = (_ExecLib)GetProcAddress(libs[index], _T("FBA_freelibrary"));
		if (dllfunc) dllfunc();
		PFrogConsole::instance()->addconsole(0, "LIBRARY %d DESTROYED", index);
		// free dll
		FreeLibrary(libs[index]);
		libsInit[index]=false;
	}

	lua_pushboolean(pL, true);
	return 1;
} // int Loader::lua_Function_FreeLibrary(lua_State *pL)



// [retval =] execlibrary(index, function [par1,par2])
int Loader::lua_Function_ExecLibrary(lua_State *pL)
{
	int numpars = lua_gettop(pL);

	// almeno 2 parametri devono esseci
	if (numpars < 2) {
		PFrogConsole::instance()->addconsole(0, "EXECLIBRARY: WRONG # OF PARAMS: %d", numpars);
		SendErrorIDE(0, "ERR||EXECLIBRARY: WRONG # OF PARAMS: %d", numpars);
		lua_pushboolean(pL, false);
		return 1;
	}

	int index=(int)lua_tonumber(pL,1);
	const char *funcname=lua_tostring (pL, 2);


	// verifica se la libreria è effettivamente caricata
	if (!libsInit[index]) {
		PFrogConsole::instance()->addconsole(0, "EXECLIBRARY: LIBRARY %d NOT LOADED!", index);
		SendErrorIDE(0, "ERR||EXECLIBRARY: LIBRARY %d NOT LOADED!", index);
		lua_pushboolean(pL, false);
		return 1;
	}
	

	// chiamata dinamica dll con argomenti variabili (non ho trovato un modo migliore per farlo)
	typedef char * (*_ExecLib) (...); 
#ifdef ARM
	TCHAR finalfname[1024];
	MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, funcname, -1, finalfname, 1024);
	_ExecLib dllfunc = (_ExecLib)GetProcAddress(libs[index], finalfname);
#else
	_ExecLib dllfunc = (_ExecLib)GetProcAddress(libs[index], funcname);
#endif
	int parc=3;

	// funzione trovata nella dll
	if ( dllfunc ) {
		switch(numpars-2) {
			case 0:		lua_pushstring( pL, dllfunc() );	break;
			case 1:		lua_pushstring( pL, dllfunc( (char *)lua_tostring(pL, parc+0) ) );	break;
			case 2:		lua_pushstring( pL, dllfunc( (char *)lua_tostring(pL, parc+0), (char *)lua_tostring(pL, parc+1) ) );	break;
			case 3:		lua_pushstring( pL, dllfunc( (char *)lua_tostring(pL, parc+0), (char *)lua_tostring(pL, parc+1), (char *)lua_tostring(pL, parc+2) ) );	break;
			case 4:		lua_pushstring( pL, dllfunc( (char *)lua_tostring(pL, parc+0), (char *)lua_tostring(pL, parc+1), (char *)lua_tostring(pL, parc+2), (char *)lua_tostring(pL, parc+3) ) );	break;
			case 5:		lua_pushstring( pL, dllfunc( (char *)lua_tostring(pL, parc+0), (char *)lua_tostring(pL, parc+1), (char *)lua_tostring(pL, parc+2), (char *)lua_tostring(pL, parc+3), (char *)lua_tostring(pL, parc+4) ) );	break;
			case 6:		lua_pushstring( pL, dllfunc( (char *)lua_tostring(pL, parc+0), (char *)lua_tostring(pL, parc+1), (char *)lua_tostring(pL, parc+2), (char *)lua_tostring(pL, parc+3), (char *)lua_tostring(pL, parc+4), (char *)lua_tostring(pL, parc+5) ) );	break;
			case 7:		lua_pushstring( pL, dllfunc( (char *)lua_tostring(pL, parc+0), (char *)lua_tostring(pL, parc+1), (char *)lua_tostring(pL, parc+2), (char *)lua_tostring(pL, parc+3), (char *)lua_tostring(pL, parc+4), (char *)lua_tostring(pL, parc+5), (char *)lua_tostring(pL, parc+6) ) );	break;
			case 8:		lua_pushstring( pL, dllfunc( (char *)lua_tostring(pL, parc+0), (char *)lua_tostring(pL, parc+1), (char *)lua_tostring(pL, parc+2), (char *)lua_tostring(pL, parc+3), (char *)lua_tostring(pL, parc+4), (char *)lua_tostring(pL, parc+5), (char *)lua_tostring(pL, parc+6), (char *)lua_tostring(pL, parc+7) ) );	break;
			case 9:		lua_pushstring( pL, dllfunc( (char *)lua_tostring(pL, parc+0), (char *)lua_tostring(pL, parc+1), (char *)lua_tostring(pL, parc+2), (char *)lua_tostring(pL, parc+3), (char *)lua_tostring(pL, parc+4), (char *)lua_tostring(pL, parc+5), (char *)lua_tostring(pL, parc+6), (char *)lua_tostring(pL, parc+7), (char *)lua_tostring(pL, parc+8) ) );	break;
			case 10:	lua_pushstring( pL, dllfunc( (char *)lua_tostring(pL, parc+0), (char *)lua_tostring(pL, parc+1), (char *)lua_tostring(pL, parc+2), (char *)lua_tostring(pL, parc+3), (char *)lua_tostring(pL, parc+4), (char *)lua_tostring(pL, parc+5), (char *)lua_tostring(pL, parc+6), (char *)lua_tostring(pL, parc+7), (char *)lua_tostring(pL, parc+8), (char *)lua_tostring(pL, parc+9) ) );	break;
			case 11:	lua_pushstring( pL, dllfunc( (char *)lua_tostring(pL, parc+0), (char *)lua_tostring(pL, parc+1), (char *)lua_tostring(pL, parc+2), (char *)lua_tostring(pL, parc+3), (char *)lua_tostring(pL, parc+4), (char *)lua_tostring(pL, parc+5), (char *)lua_tostring(pL, parc+6), (char *)lua_tostring(pL, parc+7), (char *)lua_tostring(pL, parc+8), (char *)lua_tostring(pL, parc+9), (char *)lua_tostring(pL, parc+10) ) );	break;
			case 12:	lua_pushstring( pL, dllfunc( (char *)lua_tostring(pL, parc+0), (char *)lua_tostring(pL, parc+1), (char *)lua_tostring(pL, parc+2), (char *)lua_tostring(pL, parc+3), (char *)lua_tostring(pL, parc+4), (char *)lua_tostring(pL, parc+5), (char *)lua_tostring(pL, parc+6), (char *)lua_tostring(pL, parc+7), (char *)lua_tostring(pL, parc+8), (char *)lua_tostring(pL, parc+9), (char *)lua_tostring(pL, parc+10), (char *)lua_tostring(pL, parc+11) ) );	break;
			case 13:	lua_pushstring( pL, dllfunc( (char *)lua_tostring(pL, parc+0), (char *)lua_tostring(pL, parc+1), (char *)lua_tostring(pL, parc+2), (char *)lua_tostring(pL, parc+3), (char *)lua_tostring(pL, parc+4), (char *)lua_tostring(pL, parc+5), (char *)lua_tostring(pL, parc+6), (char *)lua_tostring(pL, parc+7), (char *)lua_tostring(pL, parc+8), (char *)lua_tostring(pL, parc+9), (char *)lua_tostring(pL, parc+10), (char *)lua_tostring(pL, parc+11), (char *)lua_tostring(pL, parc+12) ) );	break;
			case 14:	lua_pushstring( pL, dllfunc( (char *)lua_tostring(pL, parc+0), (char *)lua_tostring(pL, parc+1), (char *)lua_tostring(pL, parc+2), (char *)lua_tostring(pL, parc+3), (char *)lua_tostring(pL, parc+4), (char *)lua_tostring(pL, parc+5), (char *)lua_tostring(pL, parc+6), (char *)lua_tostring(pL, parc+7), (char *)lua_tostring(pL, parc+8), (char *)lua_tostring(pL, parc+9), (char *)lua_tostring(pL, parc+10), (char *)lua_tostring(pL, parc+11), (char *)lua_tostring(pL, parc+12), (char *)lua_tostring(pL, parc+13) ) );	break;
			case 15:	lua_pushstring( pL, dllfunc( (char *)lua_tostring(pL, parc+0), (char *)lua_tostring(pL, parc+1), (char *)lua_tostring(pL, parc+2), (char *)lua_tostring(pL, parc+3), (char *)lua_tostring(pL, parc+4), (char *)lua_tostring(pL, parc+5), (char *)lua_tostring(pL, parc+6), (char *)lua_tostring(pL, parc+7), (char *)lua_tostring(pL, parc+8), (char *)lua_tostring(pL, parc+9), (char *)lua_tostring(pL, parc+10), (char *)lua_tostring(pL, parc+11), (char *)lua_tostring(pL, parc+12), (char *)lua_tostring(pL, parc+13), (char *)lua_tostring(pL, parc+14) ) );	break;
			case 16:	lua_pushstring( pL, dllfunc( (char *)lua_tostring(pL, parc+0), (char *)lua_tostring(pL, parc+1), (char *)lua_tostring(pL, parc+2), (char *)lua_tostring(pL, parc+3), (char *)lua_tostring(pL, parc+4), (char *)lua_tostring(pL, parc+5), (char *)lua_tostring(pL, parc+6), (char *)lua_tostring(pL, parc+7), (char *)lua_tostring(pL, parc+8), (char *)lua_tostring(pL, parc+9), (char *)lua_tostring(pL, parc+10), (char *)lua_tostring(pL, parc+11), (char *)lua_tostring(pL, parc+12), (char *)lua_tostring(pL, parc+13), (char *)lua_tostring(pL, parc+14), (char *)lua_tostring(pL, parc+15) ) );	break;
			case 17:	lua_pushstring( pL, dllfunc( (char *)lua_tostring(pL, parc+0), (char *)lua_tostring(pL, parc+1), (char *)lua_tostring(pL, parc+2), (char *)lua_tostring(pL, parc+3), (char *)lua_tostring(pL, parc+4), (char *)lua_tostring(pL, parc+5), (char *)lua_tostring(pL, parc+6), (char *)lua_tostring(pL, parc+7), (char *)lua_tostring(pL, parc+8), (char *)lua_tostring(pL, parc+9), (char *)lua_tostring(pL, parc+10), (char *)lua_tostring(pL, parc+11), (char *)lua_tostring(pL, parc+12), (char *)lua_tostring(pL, parc+13), (char *)lua_tostring(pL, parc+14), (char *)lua_tostring(pL, parc+15), (char *)lua_tostring(pL, parc+16) ) );	break;
			default:
				// num parametri non supportati!
				PFrogConsole::instance()->addconsole(0, "EXECLIBRARY: UNSUPPORTED PARAMS COUNT %d", numpars);
				SendErrorIDE(0, "ERR||EXECLIBRARY: UNSUPPORTED PARAMS COUNT %d", numpars);
				lua_pushboolean(pL, false);
		}
	} else {
		PFrogConsole::instance()->addconsole(0, "EXECLIBRARY: UNABLE TO CALL LIBRARY FUNCTION: %s", funcname);
		SendErrorIDE(0, "ERR||EXECLIBRARY: UNABLE TO CALL LIBRARY FUNCTION: %s", funcname);
		lua_pushboolean(pL, false);
	}
	return 1;
} // int Loader::lua_Function_ExecLibrary(lua_State *pL)


//////////////////////////////////////////////////////////////////////////////
//
// MAIN FUNCTIONS
//
//////////////////////////////////////////////////////////////////////////////


// controlla il numero di parametri da una funzione LUA, torna true se 
// è tutto ok e bisogna continuare
bool Loader::checkParams(lua_State *pL, int num_expected, char *functname, bool isdrawingfunc) 
{
	return checkParams(pL, num_expected, -1, functname, isdrawingfunc);
}

bool Loader::checkParams(lua_State *pL, int num_expected, int num_expected2, char *functname, bool isdrawingfunc)
{
	// in release, non controlliamo i parametri per massimizzare la velocità
#ifndef RELEASE_VERSION
	int numpars = lua_gettop(pL);

	if (isdrawingfunc && !DISPLAY) {
		PFrogConsole::instance()->addconsole(0, "%s CALLED BUT DISPLAY NOT AVAILABLE YET!", functname);
		SendErrorIDE(0, "ERR||%s CALLED BUT DISPLAY NOT AVAILABLE YET!", functname);
		return false;
	}

	if (numpars != num_expected && numpars != num_expected2) {
		PFrogConsole::instance()->addconsole(0, "%s WRONG # OF PARAM %d (%d, %d)", functname, 
			numpars, num_expected, num_expected2);
		SendErrorIDE(0, "ERR||%s WRONG # OF PARAM %d (%d, %d)", functname, 
			numpars, num_expected, num_expected2);
		return false;
	}
#endif
	return true;
}

Loader::Loader(
		Pixel defaultTransColor,
#ifndef RELEASE_VERSION
				DebugSock *dsock, 
#endif
				Display *display, 
#ifdef ENABLE_AUDIO
				hssSpeaker *hss_speaker, 
#endif
				PHAL::KeyList * keylist, Utils *util,
				char *_ignoredIncludeVoidScripts
				)
{
	int i;

	// app has focus when we start
	_appHasFocus = true;

	// save main objects pointers
	loader=this;
	this->util=util;
	this->keylist=keylist;

	this->_ignoredIncludeVoidScripts=_ignoredIncludeVoidScripts;

#ifdef ENABLE_AUDIO
	this->hss_speaker=hss_speaker;
#endif
	// oggetto libreria non ancora istanziato
#ifdef ENABLE_TTF_EXTENSION
	this->ft_library=NULL;
#endif
	// salva dimensioni schermo
	this->_screenWidth = display->GetWidth();
	this->_screenHeight = display->GetHeight();
	// nessun click per ora
	_lastClick.x = -1; _lastClick.y=-1;
	_mouseIsDown=0;

	// livello di blending di default
	_currentBlending=255;

	// render target di default: lo schermo
	indexRenderTarget=-1;

	// nessuna risorsa ancora aperta
	openResBuffer=NULL;
	openResLength=0;
	openResLine=NULL;
	openResNumLines=0;

	// crea smalltext per funzione luaPrint
	smalltext = new SimpleTextSmall();

	// oggetto filesystem che gestisce i files scrivibili dall'utente nell'apposita dir
	fsystem = new GameFileSystem();

#ifndef RELEASE_VERSION
	// debug step by step, per ora no
	_doNextStep=false;
	_stepByStep=true;
	_wantSetPause=false;
	_announceWhereIsDebugger=false;

	// l'editor non è ancora pronto
	_editorIsReady=false;


	// nessun breakpoint settato
	breakpoints=NULL;
	_numBreakpoints=0;

	// salva puntatore al socket di debug
	this->dsock=dsock;
	// setta call back per ricezione dati socket
	dsock->SetSocketReceiveCallBack(DebugSocketReceiveData);
#endif

	LUA = lua_open();   /* opens Lua */
	luaopen_base(LUA);  /* opens the basic library */
	luaopen_math(LUA);  /* opens the math library */
	luaopen_string(LUA);  /* opens the string library */
	luaopen_table(LUA);  /* opens the table library */
	
	luaopen_socket_core(LUA);  /* opens the socket library */
	luaopen_mime_core(LUA);		/* opens the MIME library */

	// Questo crasha, letto su un forum che si fa cosi'...
	//luaopen_package(LUA);  /* opens the package library */
	lua_pushcfunction(LUA, luaopen_package);
	lua_pushliteral(LUA, "package");
	lua_call(LUA, 1, 0);

	// aggancia hook per debugging dello script lua
#ifndef RELEASE_VERSION
	lua_sethook(LUA, luaHookRoutine, LUA_MASKCALL|LUA_MASKRET|LUA_MASKLINE, 0);;
#endif

	// colore trasparenza default
	transColor=defaultTransColor;

	// non abbiamo fatto cicli in mainloop
	mainloopCount=0;
	// non dobbiamo uscire
	_shutDown=false;

	// all'inizio non abbiamo trovato nessuna funzione nello script principale
	lua_onMainLoop_found=false;
	lua_onQuit_found=false;
	lua_onMouseDown_found=false;
	lua_onMouseUp_found=false;
	lua_onMouseMove_found=false;
	lua_onButtonDown_found=false;
	lua_onButtonUp_found=false;
	lua_HaveTo_Call_MainScript=false;
	lua_onGotFocus_found=false;
	lua_onLostFocus_found=false;
	lua_MainScript_Called=false;

	// non possiamo ancora disegnare
	DISPLAY=NULL;

	// oggetto configurazione non ancora creato
	settings=NULL;

	// per ora non abbiamo risorse allocate
	maxAllocatedImages=0;
	maxAllocatedGfxFonts=0;
	maxAllocatedLibs=0;
#ifdef ENABLE_AUDIO
	maxAllocatedMusics=0;
	maxAllocatedSounds=0;
#endif
#ifdef ENABLE_GAMEGRID
	maxAllocatedGameGrids=0;
#endif
#ifdef ENABLE_TTF_EXTENSION
	maxAllocatedFonts=0;
	fonts=NULL;
#endif
	gfxfonts=NULL;
	images=NULL;
	libs=NULL;
#ifdef ENABLE_AUDIO
	sounds=NULL;
	musics=NULL;
	musicsChannels=NULL;
	soundsChannels=NULL;
#endif
#ifdef ENABLE_GAMEGRID
	gamegrids=NULL;
#endif
	for (i = 0; i < MAX_IMAGES; i++)
		imagesInit[i]=false;
	for (i = 0; i < MAX_LIBS; i++)
		libsInit[i]=false;
#ifdef ENABLE_AUDIO
	for (i = 0; i < MAX_SOUNDS; i++)
		soundsInit[i]=false;
	for (i = 0; i < MAX_MUSICS; i++)
		musicsInit[i]=false;
#endif
#ifdef ENABLE_GAMEGRID
	for (i=0; i < MAX_GAMEGRIDS; i++)
		gamegridsInit[i]=false;
#endif
#ifdef ENABLE_TTF_EXTENSION
	for (i=0; i < MAX_FONTS; i++)
		fontsInit[i]=false;
#endif
	for (i=0; i < MAX_GFX_FONTS; i++)
		gfxfontsInit[i]=false;

	// azzera buffer keypresses
	for (i=0; i < MAX_KEYS_BUFFER; i++)
		NUMKEYPRESS[i]=0;
	
	// inizializza la tabella di conversione gradi/radianti
	for (i=0;i<360;i++)
		GRADE[i]=i*PIGRECO/180;

	// registra le chiamate LUA verso c++
	int loopcall=0;
	while ( LUA_func_table_name[loopcall] ) {
		lua_register(LUA, LUA_func_table_name[loopcall],	LUA_func_table_func[loopcall]);
		++loopcall;
	}
	PFrogConsole::instance()->addconsole(0, "* REGISTERED %d FUNCTIONS", loopcall);

	// annuncia quale funzioni hai abilitato
#ifdef ENABLE_GAMEGRID
	PFrogConsole::instance()->addconsole(0, "* GAMEGRID FUNCTIONS ENABLED");
#else
	PFrogConsole::instance()->addconsole(0, "* GAMEGRID FUNCTIONS DISABLED");
#endif
#ifdef ENABLE_AUDIO
	PFrogConsole::instance()->addconsole(0, "* AUDIO FUNCTIONS ENABLED");
#else
	PFrogConsole::instance()->addconsole(0, "* AUDIO FUNCTIONS DISABLED");
#endif
#ifdef ENABLE_TTF_EXTENSION
	PFrogConsole::instance()->addconsole(0, "* TTF FONTS FUNCTIONS ENABLED");
#else
	PFrogConsole::instance()->addconsole(0, "* TTF FONTS FUNCTIONS DISABLED");
#endif
}

Loader::~Loader(void)
{
	int i;

	// distrugge oggetto configurazione
	delete settings;
	settings=NULL;

	// distrugge oggetto filesystem
	delete fsystem;
	fsystem=NULL;

	// distruge oggetto simpletextsmall
	delete smalltext;
	smalltext=NULL;

	// distrugge tutte le gamegrids allocate
#ifdef ENABLE_GAMEGRID
	for (i = 0; i < MAX_GAMEGRIDS; i++) {
		if (gamegridsInit[i]) {
			delete gamegrids[i];
			gamegrids[i]=NULL;
			gamegridsInit[i]=false;
		}
	}
	free(gamegrids);
#endif

	// distrugge tutti i gfx fonts allocati
	for (i=0; i < MAX_GFX_FONTS; i++) {
		if (gfxfontsInit[i]) {
			delete gfxfonts[i];
			gfxfonts[i]=NULL;
			gfxfontsInit[i]=false;
		}
	}
	free(gfxfonts);

	// distrugge tutte le immagini allocate
	for (i = 0; i < MAX_IMAGES; i++) {
		_FreeImage(i);
	}
	free(images);

	// distrugge tutte le librerie allocate
	for (i = 0; i < MAX_LIBS; i++) {
		if (libsInit[i]) {
			// call library destroy
			typedef void (*_ExecLib) (void); 
			_ExecLib dllfunc = (_ExecLib)GetProcAddress(libs[i], _T("FBA_freelibrary"));
			if (dllfunc) dllfunc();
			PFrogConsole::instance()->addconsole(0, "LIBRARY %d DESTROYED", i);
			// free dll
			FreeLibrary(libs[i]);
			libs[i]=NULL;
			libsInit[i]=false;
		}
	}
	free(libs);

#ifdef ENABLE_TTF_EXTENSION
	// distrugge tutte le classi fonts allocate
	for (i = 0; i < MAX_FONTS; i++) {
		if (fontsInit[i]) {
			delete fonts[i];
			fonts[i]=NULL;
			fontsInit[i]=false;
		}
	}
	free(fonts);
	// chiude la libreria dei fonts, se caricata
	if (this->ft_library)
		FT_Done_FreeType( this->ft_library->lib );

	// distrugge la struct per il tarocco di allocazione dinamica della libreria
	delete this->ft_library;
#endif

#ifdef ENABLE_AUDIO
	// stoppa tutti i suoni e musiche
	hss_speaker->stopSounds();
	hss_speaker->stopMusics();

	// distrugge tutti i suoni allocati
	for (i = 0; i < MAX_SOUNDS; i++) {
		if (soundsInit[i]) {
			delete sounds[i];
			sounds[i]=NULL;
			soundsInit[i]=false;
		}
	}
	free(sounds);
	free(soundsChannels);

	// distrugge tutte le musiche allocate
	for (i = 0; i < MAX_MUSICS; i++) {
		if (musicsInit[i]) {
			delete musics[i];
			musics[i]=NULL;
			musicsInit[i]=false;
		}
	}
	free(musics);
	free(musicsChannels);
#endif

#ifndef RELEASE_VERSION
	// distrugge tutti i breakpoints
	ClearBreakpoints();
#endif

	// distrugge il buffer allocato per le risorse dall'ultima chiamata di openres
	free(openResBuffer);
	openResBuffer=NULL;

	// distrugge contatori linee allocate durante l'openres della risorsa
	if (openResLine) {
		for (unsigned int ii=0; ii < openResNumLines; ii++)
			delete openResLine[ii];
		free(openResLine);
		openResLine=NULL;
		openResNumLines=0;
	}

	// distrugge LUA
	if (LUA)
		lua_close (LUA);
}

bool Loader::Shutdown() { return _shutDown; }

void Loader::LoadMainScript( bool stepByStep )
{
#ifndef RELEASE_VERSION
	// decide se avviarci in modalità step by step o normale
	this->_stepByStep=stepByStep;
	// se ci avviamo in modalità debugging, segnala subito dove ti trovi
	this->_announceWhereIsDebugger=this->_stepByStep;
#endif
	// carica lo script lua (prima prova il compilato, poi quello normale)
	// nota: carico solo quello normale, pare che la funzione che prenda dal buffer
	// precompili lo script
	bool fileLoaded = true;

	LZArchive lza;
	LZItem lzi;

	// load and decompress the file
#ifdef ENABLE_SEPARATED_DAT_FOR_SCRIPTS
	if (lza.open(_T("fba.dats")) == false)
#else
	if (lza.open(_T("fba.dat")) == false)
#endif
		fileLoaded=false;
	else if (lza.read(_T("main.fba"), &lzi) == false)
		fileLoaded=false;

	if (fileLoaded) {
		
		lzi.decompress();
		unsigned char *buf = (unsigned char *)lzi.dBuffer();

		PFrogConsole::instance()->addconsole(0, "MAIN SCRIPT EXTRACTED!");

		//int scriptLoaded = luaL_loadfile(LUA, "main.fba");
		int scriptLoaded = luaL_loadbuffer (LUA,
								(const char *)buf,
								lzi.dSize(),
								"MAIN.FBA");

		switch (scriptLoaded) {
			case 0:
				PFrogConsole::instance()->addconsole(0, "MAIN SCRIPT LOADED!");
				SendErrorIDE(2, "INF||MAIN SCRIPT LOADED!");
				lua_HaveTo_Call_MainScript=true;
				break;
			case LUA_ERRSYNTAX:
			default:
				const char *error=lua_tostring (LUA, -1);
				PFrogConsole::instance()->addconsole(0, "MAIN SCRIPT NOT LOADED! %s" , error);
				SendErrorIDE(0,"ERR||MAIN SCRIPT NOT LOADED: %s", error);
				break;
		};
	} else {
		PFrogConsole::instance()->addconsole(0, "CANNOT EXTRACT MAIN SCRIPT!");
	}

}

void Loader::StylusUp( Point stylus )
{
	if (lua_onMouseUp_found && lua_MainScript_Called){
		lua_getglobal(LUA, "onstylusup");
		lua_pushnumber(LUA, stylus.x);
		lua_pushnumber(LUA, stylus.y);
		int res = lua_pcall(LUA, 2, 0, 0);
		if (res > 0) {
			const char *error=lua_tostring (LUA, -1);
			PFrogConsole::instance()->addconsole(0, "STYLUSUP ERROR %s", error);
			SendErrorIDE(0, "ERR||%s", error);
		}
	}

	_lastClick.x = -1;
	_lastClick.y = -1;
	_mouseIsDown=0;
}

void Loader::StylusDown( Point stylus )
{
	_lastClick=stylus;
	_mouseIsDown=1;


	if (lua_onMouseDown_found && lua_MainScript_Called){
		lua_getglobal(LUA, "onstylusdown");
		lua_pushnumber(LUA, stylus.x);
		lua_pushnumber(LUA, stylus.y);
		int res = lua_pcall(LUA, 2, 0, 0);
		if (res > 0) {
			const char *error=lua_tostring (LUA, -1);
			PFrogConsole::instance()->addconsole(0, "STYLUSDOWN ERROR %s", error);
			SendErrorIDE(0, "ERR||%s", error);
		}
	}
}

void Loader::StylusMove( Point stylus )
{
	_lastClick = stylus;

	if (lua_onMouseMove_found && lua_MainScript_Called){
		lua_getglobal(LUA, "onstylusmove");
		lua_pushnumber(LUA, stylus.x);
		lua_pushnumber(LUA, stylus.y);
		int res=lua_pcall(LUA, 2, 0, 0);
		if (res > 0) {
			const char *error=lua_tostring (LUA, -1);
			PFrogConsole::instance()->addconsole(0, "STYLUSMOVE ERROR %s", error);
			SendErrorIDE(0, "ERR||%s", error);
		}
	}
}

void Loader::ButtonUp(int button)
{
	// aggiorna buffer keypress
	if (button < MAX_KEYS_BUFFER)
		NUMKEYPRESS[button]=0;

	// chiama funzione lua button up
	if (lua_onButtonUp_found && lua_MainScript_Called){
		lua_getglobal(LUA, "onbuttonup");
		lua_pushnumber(LUA, button);
		int res = lua_pcall(LUA, 1, 0, 0);
		if (res > 0) {
			const char *error=lua_tostring (LUA, -1);
			PFrogConsole::instance()->addconsole(0, "BUTTONUP ERROR %s", error);
			SendErrorIDE(0, "ERR||%s", error);
		}
	}
}

// GameLostFocus
void Loader::GameLostFocus()
{
	_appHasFocus = false;

	if (lua_onLostFocus_found && lua_MainScript_Called) {

		lua_getglobal(LUA, "onlostfocus");
		int res = lua_pcall(LUA, 0, 0, 0);
		if (res > 0) {
			const char *error=lua_tostring (LUA, -1);
			PFrogConsole::instance()->addconsole(0, "ONLOSTFOCUS ERROR %s", error);
			SendErrorIDE(0, "ERR||%s", error);
		}
	}
}

// GameGotFocus
void Loader::GameGotFocus()
{
	_appHasFocus = true;

	if (lua_onGotFocus_found && lua_MainScript_Called) {

		lua_getglobal(LUA, "ongotfocus");
		int res = lua_pcall(LUA, 0, 0, 0);
		if (res > 0) {
			const char *error=lua_tostring (LUA, -1);
			PFrogConsole::instance()->addconsole(0, "ONGOTFOCUS ERROR %s", error);
			SendErrorIDE(0, "ERR||%s", error);
		}
	}
}

void Loader::ButtonDown(int button)
{
	// aggiorna buffer keypress
	if (button < MAX_KEYS_BUFFER)
		NUMKEYPRESS[button]=1; // o ++??

	// chiama funzione lua button down
	if (lua_onButtonDown_found && lua_MainScript_Called){
		lua_getglobal(LUA, "onbuttondown");
		lua_pushnumber(LUA, button);
		int res = lua_pcall(LUA, 1, 0, 0);
		if (res > 0) {
			const char *error=lua_tostring (LUA, -1);
			PFrogConsole::instance()->addconsole(0, "BUTTONDOWN ERROR %s", error);
			SendErrorIDE(0, "ERR||%s", error);
		}
	}
}

void Loader::draw(Display *display)
{
	int res;

	DISPLAY=display;
	
	// esegui lo script al primo step del mainloop, questo affinchè
	// per tutte le funzioni LUA, il display sia sempre valorizzato
	//
	if ( lua_HaveTo_Call_MainScript ) {
		// chiama lo script principale
		int scriptLoaded = lua_pcall (LUA, 0, 0, 0);
		
		lua_MainScript_Called=false;
		lua_HaveTo_Call_MainScript=false;

		switch (scriptLoaded) {
			case 0:
				PFrogConsole::instance()->addconsole(0, "MAIN SCRIPT EXECUTED!");
				SendErrorIDE(2, "INF||MAIN SCRIPT EXECUTED!");
				lua_MainScript_Called=true;
				break;
			case LUA_ERRSYNTAX:
			default:
				const char *error=lua_tostring (LUA, -1);
				PFrogConsole::instance()->addconsole(0, "MAIN SCRIPT NOT EXECUTED! %s" , error);
				SendErrorIDE(0,"ERR||MAIN SCRIPT NOT EXECUTED: %s", error);
				break;
		};

		// registra l'onmainloop
		if (lua_MainScript_Called) {
			// -----  ON MAINLOOP
			lua_getglobal(LUA, "onmainloop");
			if (!lua_isfunction(LUA, -1)) {
				PFrogConsole::instance()->addconsole(0, "FATAL: onmainloop function not found!");
				SendErrorIDE(0,"ERR||FATAL: onmainloop function not found!");
			} else {
				PFrogConsole::instance()->addconsole(0, "onmainloop function found!");
				lua_onMainLoop_found=true;
			}
			// -----  ON GOTFOCUS
			lua_getglobal(LUA, "ongotfocus");
			lua_onGotFocus_found=lua_isfunction(LUA, -1);
			// -----  ON LOSTFOCUS
			lua_getglobal(LUA, "onlostfocus");
			lua_onLostFocus_found=lua_isfunction(LUA, -1);
			// -----  ON MOUSEDOWN
			lua_getglobal(LUA, "onstylusdown");
			lua_onMouseDown_found=lua_isfunction(LUA, -1);
			// -----  ON MOUSEUP
			lua_getglobal(LUA, "onstylusup");
			lua_onMouseUp_found=lua_isfunction(LUA, -1);
			// -----  ON MOUSEMOVE
			lua_getglobal(LUA, "onstylusmove");
			lua_onMouseMove_found=lua_isfunction(LUA, -1);
			// -----  ON BUTTONDOWN
			lua_getglobal(LUA, "onbuttondown");
			lua_onButtonDown_found=lua_isfunction(LUA, -1);
			// -----  ON BUTTONUP
			lua_getglobal(LUA, "onbuttonup");
			lua_onButtonUp_found=lua_isfunction(LUA, -1);
			// -----  ON QUIT
			lua_getglobal(LUA, "onquit");
			lua_onQuit_found=lua_isfunction(LUA, -1);
		}


	}


	// chiama la mainloop nello script lua
	if (lua_onMainLoop_found) {

		lua_getglobal(LUA, "onmainloop");
		res = lua_pcall(LUA, 0, 0, 0);
		if (res > 0) {
			const char *error=lua_tostring (LUA, -1);
			PFrogConsole::instance()->addconsole(0, "ONGAMELOOP ERROR %s", error);
			SendErrorIDE(0, "ERR||%s", error);
		}
	}

	DISPLAY=NULL;

	// incrementa le pressioni dei tasti premuti
	for (res=0; res < MAX_KEYS_BUFFER; res++)
		if (NUMKEYPRESS[res] > 0) 
			++NUMKEYPRESS[res];

	// incrementa pressioni stylus
	if (_mouseIsDown > 0) ++_mouseIsDown;


	// incrementa step main loop
	++mainloopCount;
}


#ifndef RELEASE_VERSION

// setta un valore per una variabile nello stack corrente
int Loader::_FindVariableStack(lua_Debug *ar, char *varname, bool findUpValue)
{
	int vi=1;
	const char *vname;

	if ( !findUpValue ) {
		// FIND LOCAL VARIABILE
		// cerca la variabile per index (se presente) o nome
		while ((vname = lua_getlocal(LUA, ar, vi++)) != NULL) {
			lua_pop(LUA, 1);  /* remove variable value */
			// trovato indice o nome
			if ( strcmp(varname, vname) == 0 )
				return vi-1;
		}
	} else {
		// FIND UPVALUE VARIABILE
		lua_getinfo(LUA, "f", ar);  /* retrieves function */
		vi = 1;
		while ((vname = lua_getupvalue(LUA, -1, vi++)) != NULL) {
			lua_pop(LUA, 1);  /* remove upvalue value */
			// trovato indice o nome
			if ( strcmp(varname, vname) == 0 )
				return vi-1;
		}
	}

	// variabile non trovata
	return -1;
} // _FindVariableStack

bool Loader::_SetVariableStackString(char *varname, int optindex, char *newvalue, char type)
{
	lua_Debug ar;
	char tmp[4096];

	if (type == 'G') {
		// SET VARIABILE GLOBAL
		lua_pushstring(LUA, newvalue);
		lua_setglobal (LUA, varname);
		sprintf(tmp, "659||Variable string %s set %s (T:%c)", varname, newvalue, type);
		dsock->socksend(0, tmp);
		return true;
	} else {
		// SET VARIABILE LOCALE
		// recupera info stack al livello corrente
		if (lua_getstack(LUA, 0, &ar) == 0) {
			dsock->socksend(0, "600||Invalid stack level 0");
			PFrogConsole::instance()->addconsole(0, "INVALID STACK LEVEL REQUIRED %d", 0);
			return false;
		}
		// cerca la variabile
		int varindex = _FindVariableStack(&ar, varname, (type == 'U') );
		if (varindex == -1 ) {
			dsock->socksend(0, "658||Variable string not found");
			PFrogConsole::instance()->addconsole(0, "Variable string not found!");
		} else {
			lua_pushstring(LUA, newvalue);

			if (type == 'U') // setta upvalue
				lua_setupvalue(LUA, -1, varindex);
			else // setta locale
				lua_setlocal(LUA, &ar, varindex);
		
			sprintf(tmp, "659||Variable string %d set %s (T:%c)", varindex, newvalue, type);
			dsock->socksend(0, tmp);
		}
		return (varindex != -1);
	}
} // _SetVariableStackString

bool Loader::_SetVariableStackNumber(char *varname, int optindex, double newvalue, char type)
{
	lua_Debug ar;
	char tmp[4096];

	if (type == 'G') {
		// SET VARIABILE GLOBAL
		lua_pushnumber(LUA, newvalue);
		lua_setglobal (LUA, varname);
		sprintf(tmp, "659||Variable number %s set %f (T:%c)", varname, newvalue, type);
		dsock->socksend(0, tmp);
		return true;
	} else {
		// SET VARIABILE LOCALE
		// recupera info stack al livello corrente
		if (lua_getstack(LUA, 0, &ar) == 0) {
			dsock->socksend(0, "600||Invalid stack level 0");
			PFrogConsole::instance()->addconsole(0, "INVALID STACK LEVEL REQUIRED %d", 0);
			return false;
		}
		// cerca la variabile
		int varindex = _FindVariableStack(&ar, varname, (type == 'U') );
		if (varindex == -1 ) {
			dsock->socksend(0, "658||Variable number not found");
			PFrogConsole::instance()->addconsole(0, "Variable number not found!");
		} else {
			lua_pushnumber(LUA, newvalue);

			if (type == 'U') // setta upvalue
				lua_setupvalue(LUA, -1, varindex);
			else // setta locale
				lua_setlocal(LUA, &ar, varindex);

			sprintf(tmp, "659||Variable number %d set %f (T:%c)", varindex, newvalue, type);
			dsock->socksend(0, tmp);
		}
		return (varindex != -1);
	}
} // _SetVariableStackNumber

bool Loader::_SetVariableStackBoolean(char *varname, int optindex, bool newvalue, char type)
{
	lua_Debug ar;
	char tmp[4096];

	if (type == 'G') {
		// SET VARIABILE GLOBAL
		lua_pushboolean(LUA, newvalue);
		lua_setglobal (LUA, varname);
		sprintf(tmp, "659||Variable boolean %s set %d (T:%c)", varname, (newvalue?1:0), type);
		dsock->socksend(0, tmp);
		return true;
	} else {
		// recupera info stack al livello corrente
		if (lua_getstack(LUA, 0, &ar) == 0) {
			dsock->socksend(0, "600||Invalid stack level 0");
			PFrogConsole::instance()->addconsole(0, "INVALID STACK LEVEL REQUIRED %d", 0);
			return false;
		}
		// cerca la variabile
		int varindex = _FindVariableStack(&ar, varname, (type == 'U') );
		if (varindex == -1 ) {
			dsock->socksend(0, "658||Variable boolean not found");
			PFrogConsole::instance()->addconsole(0, "Variable boolean not found!");
		} else {
			lua_pushboolean(LUA, newvalue);

			if (type == 'U') // setta upvalue
				lua_setupvalue(LUA, -1, varindex);
			else // setta locale
				lua_setlocal(LUA, &ar, varindex);
			
			sprintf(tmp, "659||Variable boolean %d set %d (T:%c)", varindex, (newvalue?1:0), type);
			dsock->socksend(0, tmp);
		}
		return (varindex != -1);
	}
} // _SetVariableStackBoolean


// dati ricevuti sul socket
void Loader::OnDebugReceiveSocket(char *text)
{
	// sanity
	if (!text || strlen(text) ==0)
		return;

	// estrai parametri testo
	char *word1=strtok(text, " ");
	char *word2=strtok(NULL, " ");
	char *word3=strtok(NULL, " ");
	char tmpbuf[8192];
	bool resbool;

	if (strcmp(word1, "next") == 0 && this->_stepByStep) {

		// richiesto prossimo step
		this->_doNextStep=true;

	} else if (strcmp(word1, "pause") == 0 && !this->_stepByStep) {

		// richiesto di pausare e mettere la modalità step by step
		this->_wantSetPause=true;

	} else if (strcmp(word1, "run") == 0 && this->_stepByStep) {

		// richiesto di runnare e togliere la modalità step to step
		this->_stepByStep=false;
		this->_doNextStep=true;
		this->_announceWhereIsDebugger=false;

	} else if (strcmp(word1, "canstart") == 0) {
		
		// l'editor ci ha dato l'ok per partire
		this->_editorIsReady=true;
		PFrogConsole::instance()->addconsole(0, "EDITOR GAVE OK. WE CAN START");

	} else if ( strcmp(word1, "stack") == 0 ) {

		// dumpa lo stack corrente con tutte le variabili

	} else if ( strcmp(word1, "setlnumber") == 0 || strcmp(word1, "setgnumber") == 0 || strcmp(word1, "setunumber") == 0) {
		
		char type = 'G'; // setta un global - default
		if ( strcmp(word1, "setlnumber") == 0 ) type='L';
		else if ( strcmp(word1, "setunumber") == 0 ) type='U';

		// imposta un numero nello stack corrente
		if (word2) {
			_SetVariableStackNumber(word2, (atoi(word2) > 0 ? atoi(word2) : -1), (word3 ? atof(word3) : 0), 
				type);
		} else {
			PFrogConsole::instance()->addconsole(0, "SETNUMBER # OF PAR NOT CORRECT: 3");
			SendErrorIDE(0,"675||SETNUMBER # OF PAR NOT CORRECT: 3");
		}

	} else if ( strcmp(word1, "setlboolean") == 0 || strcmp(word1, "setgboolean") == 0 || strcmp(word1, "setuboolean") == 0) {

		char type = 'G'; // setta un global - default
		if ( strcmp(word1, "setlboolean") == 0 ) type='L';
		else if ( strcmp(word1, "setuboolean") == 0 ) type='U';

		// imposta un boolean nello stack corrente
		if (word2) {
			_SetVariableStackBoolean(word2, (atoi(word2) > 0 ? atoi(word2) : -1), (word3 && atoi(word3)==1?true:false), 
				type);
		} else {
			PFrogConsole::instance()->addconsole(0, "SETBOOLEAN # OF PAR NOT CORRECT: 3");
			SendErrorIDE(0,"675||SETBOOLEAN # OF PAR NOT CORRECT: (2) 3");
		}

	} else if ( strcmp(word1, "setlstring") == 0 || strcmp(word1, "setgstring") == 0 || strcmp(word1, "setustring") == 0) {

		char type = 'G'; // setta un global - default
		if ( strcmp(word1, "setlstring") == 0 ) type='L';
		else if ( strcmp(word1, "setustring") == 0 ) type='U';

		// Componi la stringa totale
		strcpy(tmpbuf, "");
		while (word3) {
			strcat(tmpbuf, word3);
			word3=strtok(NULL, " ");
			if (word3)
				strcat(tmpbuf, " ");
		}

		// imposta una stringa nello stack corrente
		if (word2) {
			_SetVariableStackString(word2, (atoi(word2) > 0 ? atoi(word2) : -1), tmpbuf, type);
		} else {
			PFrogConsole::instance()->addconsole(0, "SETSTRING # OF PAR NOT CORRECT: 3");
			SendErrorIDE(0,"675||SETSTRING # OF PAR NOT CORRECT: 3(2)");
		}

	} else if ( strcmp(word1, "exec") == 0 ) {
		// esegui la linea lua specificata
		// Componi la stringa totale
		strcpy(tmpbuf, "");
		while (word3) {
			strcat(tmpbuf, word3);
			word3=strtok(NULL, " ");
			if (word3)
				strcat(tmpbuf, " ");
		}

		// esegue la linea lua specificata
		if (luaL_dostring (LUA, (const char *)tmpbuf) == 0) {
			// nessun error
			SendErrorIDE(0,"496||0");
		} else {
			// errore
			SendErrorIDE(0,"497||%s", lua_tostring(LUA, -1));
		}

	} else if ( strcmp(word1, "quit") == 0 ) {

		// togli la modalità passo passo e quitta
		this->_stepByStep=false;
		this->_doNextStep=true;
		this->_shutDown=true;
		this->_announceWhereIsDebugger=false;

	} else if ( strcmp(word1, "cbreak") == 0 ) {

		// elimina tutti i breakpoints
		int rescb=ClearBreakpoints();
		PFrogConsole::instance()->addconsole(0, "BREAKPOINTS LIST CLEARED: %d", rescb);
		sprintf(tmpbuf, "810||%d", rescb);
		dsock->socksend(0, tmpbuf);

	} else if ( strcmp(word1, "break") == 0 ) {
		// switcha breakpoint
		// break nomefunzione linea
		if (word2 && word3) {
			resbool=this->SwitchBreakPoint(word2, atoi(word3));
			if (resbool) {
				PFrogConsole::instance()->addconsole(0, "BREAKPOINT ADDED: %s (%ld)", word2, atoi(word3));
				sprintf(tmpbuf, "803||ADD||%d", this->_numBreakpoints);
				dsock->socksend(0, tmpbuf);
			} else {
				PFrogConsole::instance()->addconsole(0, "BREAKPOINT REMOVED: %s (%ld)", word2, atoi(word3));
				sprintf(tmpbuf, "804||DEL||%d", this->_numBreakpoints);
				dsock->socksend(0, tmpbuf);
			}
		} else {
			PFrogConsole::instance()->addconsole(0, "INVALID BREAKPOINT");
			SendErrorIDE(0,"ERR||INVALID BREAKPOINT");
			dsock->socksend(0, "850");
		}
		// if text==break

	} else if ( strcmp(word1, "dumpmem") == 0 ) {
		lua_Debug ar;
		int vi=1;
		const char *vname;

		// recupera info stack al livello corrente
		if (lua_getstack(LUA, 0, &ar) == 0) {
			dsock->socksend(0, "600||Invalid stack level 0");
			PFrogConsole::instance()->addconsole(0, "INVALID STACK LEVEL REQUIRED %d", 0);
			return;
		}
		dsock->socksend(0, "701");	// inizio dump variabili locali
		// dumpa variabili
		while ((vname = lua_getlocal(LUA, &ar, vi++)) != NULL) {
			if (lua_isstring(LUA, -1) || lua_isnumber(LUA, -1) || lua_isboolean(LUA, -1)) {
				if ( lua_isboolean(LUA, -1) )
					sprintf(tmpbuf, "702||L||%s||%s", vname, 
						( lua_toboolean(LUA, -1) ? "true" : "false" ) );
				else
					sprintf(tmpbuf, "702||L||%s||%s", vname, lua_tostring(LUA, -1));
				dsock->socksend(0, tmpbuf);
			}
			lua_pop(LUA, 1);  /* remove variable value */
		}
		lua_getinfo(LUA, "f", &ar);  /* retrieves function */
		vi = 1;
		while ((vname = lua_getupvalue(LUA, -1, vi++)) != NULL) {
			if (lua_isstring(LUA, -1) || lua_isnumber(LUA, -1) || lua_isboolean(LUA, -1)) {
				if ( lua_isboolean(LUA, -1) )
					sprintf(tmpbuf, "702||U||%s||%s", vname, 
						( lua_toboolean(LUA, -1) ? "true" : "false" ) );
				else
					sprintf(tmpbuf, "702||U||%s||%s", vname, lua_tostring(LUA, -1));
				dsock->socksend(0, tmpbuf);
			}
			lua_pop(LUA, 1);  /* remove upvalue value */
		}

		// dump ricorsivo variabili globali
		lua_getfenv(LUA, LUA_GLOBALSINDEX);
		this->_dumpLuaTable(LUA, LUA_GLOBALSINDEX);


		dsock->socksend(0, "705");	// fine dump variabili

		// if text==dumpmem
	} else {
		// comando non riconosciuto
		PFrogConsole::instance()->addconsole(0, "RECEIVED UNKNOWN DBG COMMAND: %s", text);
		dsock->socksend(0, "999");
	}
} // void Loader::OnDebugReceiveSocket



// dumpa ricorsivamente una tabella lua sul socket
void Loader::_dumpLuaTable(lua_State* l,int idx)
{
	char tmpbuf[8192];
    lua_pushnil(l);
    while(lua_next(l,idx)!=0)
    {
		if (lua_isstring(l, -1) || lua_isnumber(l, -1) || lua_isboolean(l, -1)) {
            const char* vname=lua_tostring(l,-2);

			if ( lua_isboolean(l, -1) )
				sprintf(tmpbuf, "702||G||%s||%s", vname, 
					(lua_toboolean(l,-1)?"true":"false") 
					);
			else
				sprintf(tmpbuf, "702||G||%s||%s", vname, lua_tostring(l,-1));

			dsock->socksend(0, tmpbuf);
			/*
            int type=lua_type(l,-1);
            switch(type)
            {
				case LUA_TNUMBER:
					sprintf(tmpbuf, "702||G||%s||%f", vname, lua_tonumber(l,-1));
					dsock->socksend(0, tmpbuf);
				break;
				case LUA_TSTRING:
					sprintf(tmpbuf, "702||G||%s||%s", vname, lua_tostring(l,-1));
					dsock->socksend(0, tmpbuf);
				break;
				case LUA_TBOOLEAN:
					sprintf(tmpbuf, "702||G||%s||%d", vname, (lua_toboolean(l,-1) != 0 ? 1 : 0));
					dsock->socksend(0, tmpbuf);
				break;
				case LUA_TNIL:
					// ?
				case LUA_TTABLE:
					this->_dumpLuaTable(l, lua_gettop(l));
				break;
            }
			*/
		}
        lua_pop(l,1);
    }
} // _dumpLuaTable

// setta / unsetta breakpoint - torna true se lo aggiunge - false se lo toglie
int Loader::ClearBreakpoints()
{
	int numdel=0;
	struct breakpoint *bp;

	while (breakpoints) {

		bp=breakpoints;
		breakpoints=breakpoints->next;

		free(bp->file);
		delete bp;
		++numdel;
	}
	this->_numBreakpoints=0;
	return numdel;
}


bool Loader::EditorIsReady() { return _editorIsReady; }

bool Loader::SwitchBreakPoint(char *file, unsigned long line)
{
	char *fileup=(char *)malloc(strlen(file)+1);
	strcpy(fileup, file);

	// converti in maiuscolo
	for (unsigned int c=0; c < strlen(fileup); c++)
		fileup[c]=toupper(fileup[c]);

	// controlla se il breakpoint è già creato
	struct breakpoint *tmp=breakpoints, *prev=NULL;
	while (tmp) {
		// abbiamo trovato il nostro figlio
		if (strcmp(tmp->file, fileup) == 0 && tmp->line==line) {
			
			if (!prev)	// head remove
				breakpoints=breakpoints->next;
			else		// middle remove
				prev->next=tmp->next;
			free(tmp->file);
			delete tmp;

			--_numBreakpoints;

			free(fileup);

			return false; // rimosso
		}
		prev=tmp;
		tmp=tmp->next;
	}

	// se siamo qui, il breakpoint non esisteva quindi lo dobbiamo aggiungere
	struct breakpoint *newb=new breakpoint;
	newb->file=(char *)malloc(strlen(file)+1);
	strcpy(newb->file, fileup);
	newb->line=line;
	newb->next=breakpoints;
	breakpoints=newb;
	++_numBreakpoints;
	free(fileup);
	return true; // creato
}
#endif

// avvia un msg di errore all'ide
void Loader::SendErrorIDE(unsigned char loglevel, char *pattern, ...)
{
	// solo se non sei in modalità release ovviamente...
#ifndef RELEASE_VERSION
	// logga solo se il livello è giusto
	if (loglevel > SEND_ERRORS_IDE_LEVEL) return;

	va_list vl;
	va_start(vl, pattern);
	vsprintf(tmpbuffer, pattern, vl);
	va_end(vl);
	// aggiunge alla console
	PFrogConsole::instance()->addconsole(0, tmpbuffer);
	// aggiunge al socket, se connesso
	if (dsock->isConnected()) {
		dsock->socksend(0, tmpbuffer);
	}
#endif
}

// distrugge una pic allocata e setta flag di init a falsa
void Loader::_FreeImage(int index)
{
	// libera immagine se già allocata
	if (imagesInit[index]) {
		delete images[index];
		images[index]=NULL;
		imagesInit[index]=false;
	}	
	// se era il render target, resettalo
	if (index == this->indexRenderTarget) {
		this->indexRenderTarget = -1;
		if (DISPLAY) {
			DISPLAY->SetRenderTarget(0);
			SendErrorIDE(3, "INF||RENDERTARGET RESET BECAUSE FREEIMAGE %d", index);
		}
		else
			SendErrorIDE(0, "ERR||CANNOT RESET RENDERTARGET BECAUSE SCREEN IS NOT SET!");
	}
}

// torna il livello di blending corrente
unsigned char Loader::CurrentBlending() { return this->_currentBlending; }

// Evento richiamato dalla main class quando il loader sta per essere distrutto
void Loader::SignalQuit()
{
	// distruggi l'engine dei socket
#ifdef SOCKET_MODULE
	luaCloseSocketEngine(LUA);
#endif
	// Se nello script c'è l'evento onquit, richiamalo
	if ( this->lua_onQuit_found ) {
		lua_getglobal(LUA, "onquit");
		int res = lua_pcall(LUA, 0, 0, 0);
	}
}
