/*  TA3D, a remake of Total Annihilation
    Copyright (C) 2005  Roland BROCHARD

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA*/

/*----------------------------------------------------------------------\
|                                script.cpp                             |
|      contient les classes nécessaires à la gestion des scripts de     |
| controle du déroulement de la partie. Les scripts peuvent influencer  |
| considérablement le déroulement de la partie en manipulant les unités |
| les ressources mais aussi l'écran et déclenche les signaux de défaite |
| et de victoire.                                                       |
\----------------------------------------------------------------------*/

#include <allegro.h>
#include <alleggl.h>
#include <GL/glu.h>
#include "console.h"
#include "ta3dbase.h"
#include "EngineClass.h"
#include "script.h"

int		nb_op=54;
char	*op[]={"+","-","*","/","%","&&","||","^","!","imp","eqv","=","<",">","<=",">=","!=","exp","log","sqrt","cos","sin","rand","abs","tan","cotan","sh","ch","th","coth","acos","asin","atan","ach","ash","ath","mouse_x","mouse_y","mouse_z","mouse_b","get_key","Int","time","load","nb_player","get_unit_number_for_player","get_unit_owner","get_unit_number","annihilated","has_unit","create_unit","map_w","map_h","player_side"};	// Opérateurs
byte	pr[]={  4,  4,  5,  5,  5,   2,   2,  2,  2,    2,    2,  1,  3,  3,   3,   3,   3,    2,    2,     2,    2,    2,     2,    2,    2,      2,   2,   2,   2,     2,     2,     2,     2,    2,    2,    2,       10,       10,       10,       10,       10,    2,    10,     2,          10,                         10,               10,              10,           10,        10,           10,     10,     10,           10};	// Priorités
byte	un[]={  0,  0,  0,  0,  0,   0,   0,  0,  1,    0,    0,  0,  0,  0,   0,   0,   0,    1,    1,     1,    1,    1,     1,    1,    1,      1,   1,   1,   1,     1,     1,     1,     1,    1,    1,    1,        2,        2,        2,        2,        2,    1,     2,     1,           2,                          1,                1,               1,            1,         1,            1,      2,      2,            1};	// Unaire ?? (ou sans paramètre = 2)

int		nb_cmd=41;
char	*cmd[]={"if","then","else","for","to","while","cls","do","until","end","print","logmsg","line","point","triangle","signal",
				"next","loop","locate","color","box","fillbox","wend","circle","sleep","wait","new","int","float","bitmap",
				"put","get","save","destroy","create","set_current_player","change_unit_owner","move_unit","kill_unit","kick_unit",
				"play"};

char tmp_buf[100];

void ANALYSE::analyse(char *text)
{
	destroy();		// Au cas où on aurait déjà analysé quelque chose
	char *cur=text;
	while(cur[0]) {
		while(cur[0]==' ' || cur[0]==8 || cur[0]==9 || cur[0]==10 || cur[0]==13)	cur++;		// Saute les espaces

		char *end=cur;					// Détecte la fin du mot
		if(cur[0]=='/' && cur[1]=='/' || cur[0]=='#') {		// Commentaires
			break;
			}
		switch(cur[0])
		{
		case ',':
			end++;
			break;
		case '(':				// On compte un mot par parenthèse
		case ')':
			end++;
			break;
		case '-':
		case '=':
		case '+':
		case '*':
		case '/':
		case '<':
		case '>':
		case '^':
		case '!':
		case '|':
		case '&':
		case '%':
			while(end[0]=='=' || end[0]=='-' || end[0]=='+' || end[0]=='*' || end[0]=='/' || end[0]=='>' || end[0]=='<' || end[0]=='^' || end[0]=='&' || end[0]=='|' || end[0]=='%' || end[0]=='!')	end++;
			break;
		case '"':
			end++;
			while(end[0]!='"' && end[0]!=10 && end[0]!=13 && end[0]!=0)	end++;
			end++;
			break;
		default:
			while(end[0]!=0 && end[0]!=' ' && end[0]!=8 && end[0]!=9 && end[0]!=10 && end[0]!=13 && end[0]!='(' && end[0]!=')' && end[0]!='|' && end[0]!='&' && end[0]!='%' &&
			end[0]!='=' && end[0]!='+' && end[0]!='-' && end[0]!='*' && end[0]!='/' && end[0]!='>' && end[0]!='<' && end[0]!='^' && end[0]!='!' && end[0]!=',')	end++;
		};
		if(end==cur)	break;

		char rem=end[0];
		end[0]=0;
		A_WORD w;
		w.name=strdup(cur);
		end[0]=rem;				// Restore les données effacées
		w.type=WORD_TYPE_NONE;
		w.val=0;
		w.f=0.0f;
		w.id=0;

		if(w.name[0]==',') {
			w.id=0;
			w.type=WORD_TYPE_VIRGULE;
			}
		if(w.name[0]=='(') {
			w.id=P_ID_1;
			w.type=WORD_TYPE_PARENTHESE;
			}
		else if(w.name[0]==')') {
			w.id=P_ID_2;
			w.type=WORD_TYPE_PARENTHESE;
			}

		for(int i=0;i<nb_cmd;i++)					// Vérifie s'il s'agit d'une commande interne
			if(strcasecmp(w.name,cmd[i])==0) {
				w.id=i;
				w.type=WORD_TYPE_COMMAND;
				break;
				}

		for(int i=0;i<nb_op;i++)					// Vérifie s'il s'agit d'un opérateur
			if(strcasecmp(w.name,op[i])==0) {
				w.id=i;
				w.type=WORD_TYPE_OP;
				break;
				}

		add_word(w);

		cur=end;
		}
}

void ASM_PROGRAM::compile(char *filename)				// Compile un fichier source
{
	destroy();					// Ecrase le code éventuellement déjà chargé
	FILE *file[10];
	int cur_file=0;
	file[cur_file]=fopen(filename,"rb");
	if(file[cur_file]==NULL)	return;				// Echec

	char buf[10000];			// Lignes de 10000 caractères maxi (devrait être suffisant)

	ANALYSE			analyse;			// Analyseur syntaxique
	EVAL_TREE		*eval_tree=NULL;	// Arbre d'évaluation
	STRUCT_STACK	s_stack;			// Pile de structures

	int				nb_define=0;		// Nombre d'objets définis par #define
	char			*def_name[10000];
	char			*def_text[10000];

	char *f=NULL;
	while((f=fgets(buf,1000,file[cur_file]))!=NULL || cur_file>0) {		// Tant qu'on n'a pas atteint la fin du fichier
		if(f==NULL) {						// Descend d'un niveau d'inclusion
			fclose(file[cur_file]);
			cur_file--;
			if(cur_file>=0)	continue;
			break;
			}
		printf("%s",buf);		// Affiche la ligne en cours de traitement

		char *fg=buf;
		while(strstr(fg,"//")) {	// Enlève les commentaires
			char *g=strstr(fg,"//");
			bool ok=(g==fg);
			if(!ok) {
				char *p=fg;
				ok=true;
				while(p!=g) {
					p++;
					if(p[0]=='"')	ok^=true;
					}
				}
			if(ok)
				g[0]=0;
			else
				fg=g+1;
			}

		if(strstr(buf,"#define ")) {					// Définit un objet préprocesseur
			char *p=strstr(buf,"#define ");
			bool check=true;
			int i=0;
			while(buf[i]!='#') {				// Vérifie qu'il ne s'agit pas d'un commentaire
				if(buf[i]!=' ' && buf[i]!=9 && buf[i]!=8) {
					check=false;
					break;
					}
				i++;
				}
			if(strncmp(buf+i,"#define ",8)==0) {		// Si ce n'est pas en commentaire
				p+=8;
				while(p[0]==32 || p[0]==8 || p[0]==9)	p++;
				char *name=p;
				while(p[0]!=0 && p[0]!=8 && p[0]!=9 && p[0]!=32)	p++;
				char old=p[0];
				p[0]=0;
				name=strdup(name);
				p[0]=old;

				int idx=-1;
				for(i=0;i<nb_define;i++)				// Vérifie si on ne l'a pas déjà
					if(strcmp(def_name[i],name)==0) {
						idx=i;
						break;
						}

				while(p[0]==32 || p[0]==8 || p[0]==9)	p++;
				if(idx==-1) {
					idx=nb_define++;
					def_name[idx]=name;
					}
				else {
					free(name);
					free(def_text[idx]);
					}

				def_text[idx]=strdup(p);

				continue;
				}
			}
		else {				// Remplace les objets préprocesseur
			bool change;
			do {
				change=false;
				for(int i=0;i<nb_define;i++)
					if(strstr(buf,def_name[i])) {
						bool ok=true;
						char *fg=buf;
						char *g=strstr(buf,def_name[i]);
						while(fg!=g) {
							if(fg[0]=='"')	ok^=true;
							fg++;
							}
						if(ok) {
							change=true;
							memmove(g+strlen(def_text[i]),g+strlen(def_name[i]),strlen(g+strlen(def_name[i])));
							memcpy(g,def_text[i],strlen(def_text[i])+1);
							}
						}
				}while(change);
			}

		if(strstr(buf,"#include ") && cur_file<9) {						// Si on peut inclure un fichier on le fait
			char *p=strstr(buf,"#include ");
			bool check=true;
			int i=0;
			while(buf[i]!='#') {				// Vérifie qu'il ne s'agit pas d'un commentaire
				if(buf[i]!=' ' && buf[i]!=9 && buf[i]!=8) {
					check=false;
					break;
					}
				i++;
				}
			if(strncmp(buf+i,"#include ",9)==0) {		// Si ce n'est pas en commentaire
				p+=9;
				while(p[0]==32 || p[0]==8 || p[0]==9 || p[0]=='"')	p++;
				if(strstr(p,"\""))
					*(strstr(p,"\""))=0;
				char tmp[200];
				tmp[0]=0;
				strcat(tmp,"scripts/");
				strcat(tmp,p);
				file[++cur_file]=fopen(tmp,"rb");
				if(file[cur_file]==NULL) {
					file[cur_file]=fopen(p,"rb");
					if(file[cur_file]==NULL)				// Echec
						cur_file--;
					}
				continue;
				}
			}

		analyse.analyse(buf);
		printf("%d mots\n",analyse.nb);

		for(int i=0;i<analyse.nb;i++)				// Vérifie les variables
			if(analyse.word[i].type==WORD_TYPE_NONE) {
				if(is_val(&(analyse.word[i]))) {
					analyse.word[i].type=WORD_TYPE_VAL;
					}
				else {
					analyse.word[i].type=WORD_TYPE_VAR;
					analyse.word[i].val=-1;							// Ce n'est pas un tableau
					char *st;
					if(st=strstr(analyse.word[i].name,"["))			// Si on a affaire à un tableau
						if(strstr(st,"]")) {
							if(st[1]>='0' && st[1]<='9') {			// Entier
								analyse.word[i].val=atoi(st+1);			// Indice ou taille du tableau
								analyse.word[i].f=0.0f;					// Indice constant
								*st=0;									// Enlève l'indice entre crochets
								}
							else {									// Variable
								*(strstr(st,"]"))=0;
								analyse.word[i].val=get_var_id(st+1);	// Indice ou taille du tableau (variable)
								analyse.word[i].f=1.0f;					// Indice variable
								*st=0;									// Enlève l'indice entre crochets
								}
							}
					analyse.word[i].id=get_var_id(analyse.word[i].name);
					if(analyse.word[i].id==-1)			// Si la variable n'existe pas
						analyse.word[i].id=add_var(analyse.word[i].name);				// Ajoute une variable
					}
				}

		int first=0;
		bool done=false;
		bool first_analysis=true;
		int last_code=-1;
		int first_exp_pos=size;
		int second_exp_pos=size;		// Début de la seconde expression dans le code compilé

		do
		{
		while(first<analyse.nb && analyse.word[first].type==WORD_TYPE_COMMAND)	first++;		// Détecte le premier mot nécessitant une analyse

		if(first<analyse.nb) {					// Utilise un arbre d'évaluation pour évaluer dans l'ordre l'expression
			if(eval_tree)	{	eval_tree->destroy();	delete eval_tree;	}
			eval_tree=new EVAL_TREE;
			eval_tree->init();
			eval_tree->id=first;
			bool old_was=true;
			EVAL_TREE *parentheses[1000];		// Jusqu'à 1000 parenthèses ouvrantes en même temps ça devrait suffir!!
			int	nb_parentheses=0;
			if(analyse.word[first].type!=WORD_TYPE_OP) {
				if(analyse.word[first].type==WORD_TYPE_PARENTHESE) {
					eval_tree->pr=100000;
					old_was=false;
					parentheses[nb_parentheses++]=eval_tree;		// Mémorise la position du père de la parenthèse ouvrante
					}
				else {
					eval_tree->pr=10;
					old_was=true;
					}
				}
			else {
				old_was=false;
				if(un[analyse.word[first].id]!=2)
					eval_tree->unary=un[analyse.word[first].id];
				eval_tree->pr=pr[analyse.word[eval_tree->id].id];
				}
			int i=first+1;
			EVAL_TREE *old=eval_tree;
			bool first_is_alone=analyse.word[first].type==WORD_TYPE_OP && un[analyse.word[first].id]==2;
			old_was|=first_is_alone;
			while(i<analyse.nb && (analyse.word[i].type==WORD_TYPE_OP || analyse.word[i].type==WORD_TYPE_PARENTHESE || ((analyse.word[i].type==WORD_TYPE_VAR || analyse.word[i].type==WORD_TYPE_VAL) && !old_was))) {		// Pour les opérateurs
				if(analyse.word[i].type==WORD_TYPE_PARENTHESE) {		// Gère les parenthèses
					if((old_was || first_is_alone) && analyse.word[i].id==P_ID_1)	break;
					switch(analyse.word[i].id)
					{
					case P_ID_1:				// Ouvrante
						{
						EVAL_TREE *tree=new EVAL_TREE;
						tree->init();
						tree->id=i++;
						tree->pr=100000;		// Priorité absolue
						old_was=false;			// On ne peut pas remonter la parenthèse
						old->d=tree;
						old=tree;
						parentheses[nb_parentheses++]=tree;		// Mémorise la position du père de la parenthèse ouvrante
						}
						break;
					case P_ID_2:				// Fermante
						nb_parentheses--;
						old_was=true;
						parentheses[nb_parentheses]->g=parentheses[nb_parentheses]->d;		// Déplace les données sur la branche de gauche
						parentheses[nb_parentheses]->d=NULL;
						old=parentheses[nb_parentheses];
						i++;
						break;
					};
					continue;
					}

					// Un signe moins qui n'est pas un opérateur
				if(analyse.word[i].type==WORD_TYPE_OP && analyse.word[i].id==OP_SUBS && ((analyse.word[i-1].type==WORD_TYPE_OP && un[analyse.word[i-1].id]!=2) || (analyse.word[i-1].type==WORD_TYPE_PARENTHESE && analyse.word[i-1].id==P_ID_1))) {
					i++;
					char *tmp=(char*) malloc(strlen(analyse.word[i].name)+2);
					tmp[0]=0;
					strcat(tmp,"-");
					strcat(tmp,analyse.word[i].name);
					free(analyse.word[i].name);
					analyse.word[i].name=tmp;
					}
				if(old_was && analyse.word[i].type==WORD_TYPE_OP && un[analyse.word[i].id])	// Fin de l'expression
					break;
				else if(first_is_alone && analyse.word[i].type==WORD_TYPE_OP && un[analyse.word[i].id])	// Fin de l'expression
					break;
				else if(first_is_alone && analyse.word[i].type!=WORD_TYPE_OP)	// Fin de l'expression
					break;
				first_is_alone=false;
				EVAL_TREE *tree=new EVAL_TREE;
				tree->init();
				tree->id=i++;
				if(analyse.word[tree->id].type!=WORD_TYPE_OP || un[analyse.word[tree->id].id]==2) {				// Variable / valeur
					tree->pr=10;
					old_was=true;
					old->d=tree;
					}
				else {													// Opérateur
					old_was=false;
					if(analyse.word[tree->id].id==11 && tree->id>1 && (analyse.word[0].type!=WORD_TYPE_COMMAND || analyse.word[0].id!=CMD_FOR))
						tree->pr=3;
					else
						tree->pr=pr[analyse.word[tree->id].id];
					tree->unary=un[analyse.word[tree->id].id];
					if(!tree->unary) {
						tree->g=old->d;
						tree->d=NULL;
						old->d=tree;
						}
					else {
						tree->g=NULL;
						tree->d=NULL;
						old->d=tree;
						}
					old=tree;
					}
				}
			eval_tree->fix_pr();
			eval_tree->print(analyse.word);	printf("\n");

			int index[i-first];			// Tableau d'indices pour l'ordre des opérations
			int limit=eval_tree->postfix(index,0);		// Ordre de l'expression postfixée

			if(first_analysis)
				last_code=add_code(ASM_CLEAR);		// clear
			for(int e=0;e<limit;e++)			// Création du code associé
				switch(analyse.word[index[e]].type)
				{
				case WORD_TYPE_VAL:			// Valeur spécifiée
					last_code=-1;
					{
					int nb=1;
					while(e+nb<limit && analyse.word[index[e+nb]].type==WORD_TYPE_VAL)	nb++;
					if(nb==1) {
						VAR *tmp_var=get_val_from_word(&analyse.word[index[e]]);
						add_code(ASM_PUSH_VAL);		// push_val
						switch(tmp_var->type)
						{
						case VAR_INTEGER:
							add_code(ASM_CODE_INT);
							add_int(tmp_var->val);
							break;
						case VAR_FLOATING:
							add_code(ASM_CODE_FLT);
							add_float(tmp_var->f);
							break;
						case VAR_STRING:
							add_code(ASM_CODE_STR);
							add_string((char*)tmp_var->s);
							break;
						};
						delete tmp_var;
						}
					else {
						add_code(ASM_PUSH_VALS);		// push_vals
						add_short(nb);
						for(int k=0;k<nb;k++) {
							VAR *tmp_var=get_val_from_word(&analyse.word[index[e]]);
							switch(tmp_var->type)
							{
							case VAR_INTEGER:
								add_code(ASM_CODE_INT);
								add_int(tmp_var->val);
								break;
							case VAR_FLOATING:
								add_code(ASM_CODE_FLT);
								add_float(tmp_var->f);
								break;
							case VAR_STRING:
								add_code(ASM_CODE_STR);
								add_string((char*)tmp_var->s);
								break;
							};
							delete tmp_var;
							e++;
							}
						e--;
						}
					}
					break;
				case WORD_TYPE_VAR:			// Variable
					if(!(index[e]==0 || (index[e]==1 && analyse.word[0].type==WORD_TYPE_COMMAND && (analyse.word[0].id==CMD_FOR || analyse.word[0].id==CMD_NEW || analyse.word[0].id==CMD_CREATE || analyse.word[0].id==CMD_GET || analyse.word[0].id==CMD_DESTROY)))) {
						if(analyse.word[index[e]].val>=0) {			// Elément de tableau
							add_code(ASM_ARRAY_PUSH);
							add_short(analyse.word[index[e]].id);
							if(analyse.word[index[e]].f==0.0f) {
								add_code(ASM_CODE_VAL);
								add_int(analyse.word[index[e]].val);
								}
							else {
								add_code(ASM_CODE_VAR);
								add_short(analyse.word[index[e]].val);
								}
							last_code=-1;
							}
						else if(last_code!=-1) {
							switch(code[last_code])
							{
							case ASM_PUSH_VAR:						// Réécrit une partie du code
								{
									short o_idx=*((short*)(&(code[last_code+1])));;
									size=last_code;
									last_code=add_code(ASM_PUSH_VARS);					// push vars
									add_short(2);
									add_short(o_idx);
									add_short(analyse.word[index[e]].id);				// identifiant de la variable
								}
								break;
							case ASM_PUSH_VARS:
								{
									*((short*)(&(code[last_code+1])))=*((short*)(&(code[last_code+1])))+1;
									add_short(analyse.word[index[e]].id);				// identifiant de la variable
								}
								break;
							default:
								last_code=add_code(ASM_PUSH_VAR);					// push var
								add_short(analyse.word[index[e]].id);				// identifiant de la variable
							};
							}
						else {
							last_code=add_code(ASM_PUSH_VAR);					// push var
							add_short(analyse.word[index[e]].id);				// identifiant de la variable
							}
					}
					break;
				case WORD_TYPE_OP:			// Opérateur
					last_code=-1;
					switch(analyse.word[index[e]].id)
					{
					case OP_ADD:		add_code(ASM_ADD);		break;
					case OP_SUBS:		add_code(ASM_SUB);		break;
					case OP_MUL:		add_code(ASM_MUL);		break;
					case OP_DIV:		add_code(ASM_DIV);		break;
					case OP_MOD:		add_code(ASM_MOD);		break;
					case OP_AND:		add_code(ASM_AND);		break;
					case OP_OR:			add_code(ASM_OR);		break;
					case OP_XOR:		add_code(ASM_XOR);		break;
					case OP_NOT:		add_code(ASM_NOT);		break;
					case OP_IMP:		add_code(ASM_IMP);		break;
					case OP_EQV:		add_code(ASM_EQV);		break;
					case OP_LESS:		add_code(ASM_LESS);		break;
					case OP_GREATER:	add_code(ASM_GREATER);	break;
					case OP_LEQUAL:		add_code(ASM_LEQUAL);	break;
					case OP_GEQUAL:		add_code(ASM_GEQUAL);	break;
					case OP_NEQUAL:		add_code(ASM_NEQUAL);	break;
					case OP_EQUAL:
						if(index[e]==1 || (index[e]==2 && analyse.word[0].type==WORD_TYPE_COMMAND && analyse.word[0].id==CMD_FOR)) {			// Affectation
							if(analyse.word[index[e]-1].val==-1) {
								add_code(ASM_AFFECT);					// Affectation
								add_short(analyse.word[index[e]-1].id);	// identifiant de la variable
								}
							else {
								add_code(ASM_ARRAY_AFFECT);				// Affectation à un élément de tableau
								add_short(analyse.word[index[e]-1].id);	// identifiant de la variable
								if(analyse.word[index[e]-1].f==0.0f) {
									add_code(ASM_CODE_VAL);
									add_int(analyse.word[index[e]-1].val);	// Indice dans le tableau
									}
								else {
									add_code(ASM_CODE_VAR);
									add_short(analyse.word[index[e]-1].val);	// Indice dans le tableau
									}
								}
							}
						else
							add_code(ASM_EQUAL);
						break;
					case OP_EXP:		add_code(ASM_EXP);	break;
					case OP_LOG:		add_code(ASM_LOG);	break;
					case OP_SQRT:		add_code(ASM_SQRT);	break;
					case OP_COS:		add_code(ASM_COS);	break;
					case OP_SIN:		add_code(ASM_SIN);	break;
					case OP_RAND:		add_code(ASM_RAND);	break;
					case OP_ABS:		add_code(ASM_ABS);	break;
					case OP_TAN:		add_code(ASM_TAN);	break;
					case OP_COTAN:		add_code(ASM_COTAN);	break;
					case OP_SH:			add_code(ASM_SH);	break;
					case OP_CH:			add_code(ASM_CH);	break;
					case OP_TH:			add_code(ASM_TH);	break;
					case OP_COTH:		add_code(ASM_COTH);	break;
					case OP_ACOS:		add_code(ASM_ACOS);	break;
					case OP_ASIN:		add_code(ASM_ASIN);	break;
					case OP_ATAN:		add_code(ASM_ATAN);	break;
					case OP_ACH:		add_code(ASM_ACH);	break;
					case OP_ASH:		add_code(ASM_ASH);	break;
					case OP_ATH:		add_code(ASM_ATH);	break;
					case OP_INT:		add_code(ASM_INT);	break;
					case OP_MOUSE_X:	add_code(ASM_MOUSE_X);	break;
					case OP_MOUSE_Y:	add_code(ASM_MOUSE_Y);	break;
					case OP_MOUSE_Z:	add_code(ASM_MOUSE_Z);	break;
					case OP_MOUSE_B:	add_code(ASM_MOUSE_B);	break;
					case OP_GET_KEY:	add_code(ASM_GET_KEY);	break;
					case OP_TIME:		add_code(ASM_TIME);	break;
					case OP_LOAD:		add_code(ASM_LOAD);	break;
					case OP_NB_PLAYER:	add_code(ASM_NB_PLAYER);	break;
					case OP_GET_UNIT_NUMBER_FOR_PLAYER:	add_code(ASM_GET_UNIT_NUMBER_FOR_PLAYER);	break;
					case OP_GET_UNIT_OWNER:	add_code(ASM_GET_UNIT_OWNER);	break;
					case OP_GET_UNIT_NUMBER:	add_code(ASM_GET_UNIT_NUMBER);	break;
					case OP_ANNIHILATED:	add_code(ASM_ANNIHILATED);	break;
					case OP_HAS_UNIT:	add_code(ASM_HAS_UNIT);	break;
					case OP_CREATE_UNIT:	add_code(ASM_CREATE_UNIT);	break;
					case OP_MAP_W:		add_code(ASM_MAP_W);	break;
					case OP_MAP_H:		add_code(ASM_MAP_H);	break;
					case OP_PLAYER_SIDE:	add_code(ASM_PLAYER_SIDE);	break;
					};
					break;
				case WORD_TYPE_FUNCTION:	// Fonction
					break;
				case WORD_TYPE_COMMAND:		// Commande interne
					break;
				case WORD_TYPE_PARENTHESE:	// Parenthèse
					break;
				};
			first=i;
			if(first_analysis)
				second_exp_pos=size;		// Début de la seconde expression dans le code compilé
			first_analysis=false;
			}
		else
			done=true;
		}while(!done);
		if(first>0)
			switch(analyse.word[0].type)
			{
			case WORD_TYPE_FUNCTION:
				break;
			case WORD_TYPE_COMMAND:
				switch(analyse.word[0].id)
				{
				case CMD_PRINT:				// Commande d'affichage
					add_code(ASM_PRINT);					break;
				case CMD_LOGMSG:
					add_code(ASM_LOGMSG);					break;
				case CMD_LINE:
					add_code(ASM_LINE);						break;
				case CMD_POINT:
					add_code(ASM_POINT);					break;
				case CMD_TRIANGLE:
					add_code(ASM_TRIANGLE);					break;
				case CMD_SIGNAL:
					add_code(ASM_SIGNAL);					break;
				case CMD_LOCATE:
					add_code(ASM_LOCATE);					break;
				case CMD_COLOR:
					add_code(ASM_COLOR);					break;
				case CMD_BOX:
					add_code(ASM_BOX);						break;
				case CMD_FILLBOX:
					add_code(ASM_FILLBOX);					break;
				case CMD_CLS:
					add_code(ASM_CLS);						break;
				case CMD_CIRCLE:
					add_code(ASM_CIRCLE);					break;
				case CMD_SLEEP:
					add_code(ASM_SLEEP);					break;
				case CMD_WAIT:
					add_code(ASM_WAIT);						break;
				case CMD_FOR:										// Boucle for	(ajoute une boucle sur la pile de structures)
					{
						STRUCT s_for;
						s_for.type=STRUCT_FOR;
						s_for.start_pos=second_exp_pos;			// Mémorise la position du début de la boucle

							// Situation : l'expression donnant la valeur limite est sur la pile, la variable à comparer n'est nulle part (sauf premier passage)
							// donc on la place sur la pile:
						add_code(ASM_PUSH_VAR);
						add_short(analyse.word[1].id);						// identifiant de la variable à comparer
							// Ensuite on peut comparer les 2 valeurs de la pile et on conclu
						add_code(ASM_IF_LESS);		// On saute le contenu de la boucle si la limite est atteinte

						s_for.pos=size;				// Position du morceau de code à modifier en rencontrant NEXT
						add_int(0);					// On ne sait pas encore où sauter mais ça viendra

						s_for.limit=analyse.word[1].id;		// Mémorise l'identifiant de la variable à tester

						s_stack.push(s_for);		// Empile la boucle
					}
					break;
				case CMD_NEXT:										// Fin de boucle for
					{
						STRUCT s_for=s_stack.pop();
						if(s_for.type==STRUCT_FOR) {
							add_code(ASM_NEXT);
							add_short(s_for.limit);		// La variable à tester
							add_int(s_for.start_pos);	// au début de la boucle*/
							*((int*)(&code[s_for.pos]))=size;	// Indique la position de l'instruction suivante
							}
						else
							printf("erreur de syntaxe!! : %d\n",s_for.type);
					}
					break;
				case CMD_DO:										// Boucle do (while/until)
					{
						STRUCT s_do;
						s_do.type=STRUCT_DO;
						s_do.start_pos=first_exp_pos;

						if(analyse.word[1].id==CMD_WHILE)			// do while
							add_code(ASM_IF_NOT);			// Si la condition devient fausse (while)
						else
							add_code(ASM_IF);			// On saute le code
						s_do.pos=size;
						add_int(0);

						s_stack.push(s_do);
					}
					break;
				case CMD_LOOP:										// Fin de boucle do
					{
						STRUCT s_do=s_stack.pop();
						add_code(ASM_JMP);
						add_int(s_do.start_pos);
						*((int*)(&code[s_do.pos]))=size;	// Indique la position de l'instruction suivante
					}
					break;
				case CMD_WHILE:										// Boucle while
					{
						STRUCT s_while;
						s_while.type=STRUCT_WHILE;
						s_while.start_pos=first_exp_pos;

						add_code(ASM_IF_NOT);		// On saute le bloc si la condition devient fausse (while)
						s_while.pos=size;
						add_int(0);

						s_stack.push(s_while);
					}
					break;
				case CMD_WEND:										// Fin de boucle while
					{
						STRUCT s_while=s_stack.pop();
						add_code(ASM_JMP);
						add_int(s_while.start_pos);
						*((int*)(&code[s_while.pos]))=size;	// Indique la position de l'instruction suivante
					}
					break;
				case CMD_IF:										// Instruction conditionnelle
					{
						STRUCT s_if;
						s_if.type=STRUCT_IF;
						s_if.start_pos=second_exp_pos;

						add_code(ASM_IF_NOT);						// Saute le bloc de code suivant IF si besoin
						s_if.pos=size;
						add_int(0);									// Saute le bloc

						s_stack.push(s_if);
					}
					break;
				case CMD_ELSE:										// Fin de structure IF pour début nouvelle structure IF
					{
						STRUCT s_if=s_stack.pop();
						STRUCT s_else;
						s_else.type=STRUCT_IF;
						s_else.start_pos=second_exp_pos;

						add_code(ASM_JMP);							// Saute le bloc suivant ELSE
						s_else.pos=size;
						add_int(0);

						*((int*)(&code[s_if.pos]))=size;			// Indique à l'instruction IF où elle doit sauter

						s_stack.push(s_else);
					}
					break;
				case CMD_END:										// Fin de structure (éventuellement fin de programme)
					if(analyse.nb>1)
						switch(analyse.word[1].id)
						{
						case CMD_IF:								// Fin de structure IF/THEN/ELSE
							{
								STRUCT s_if=s_stack.pop();

								*((int*)(&code[s_if.pos]))=size;	// Indique où on doit sauter si on saute le bloc
							}
							break;
						}
					else
						add_code(ASM_END);
					break;
				case CMD_NEW:										// Déclaration d'une variable
					if(analyse.word[1].type==WORD_TYPE_VAR && analyse.word[2].type==WORD_TYPE_COMMAND) {
						add_code(ASM_NEW);
						add_short(analyse.word[1].id);		// Identifiant de la variable
						if(analyse.word[3].id==CMD_INTEGER) {
							if(analyse.word[1].val==-1)
								add_code(VAR_INTEGER);
							else {
								add_code(VAR_ARRAY_INTEGER);
								if(analyse.word[1].f==0.0f) {
									add_code(ASM_CODE_VAL);
									add_int(analyse.word[1].val);
									}
								else {
									add_code(ASM_CODE_VAR);
									add_short(analyse.word[1].val);
									}
								}
							}
						else if(analyse.word[3].id==CMD_FLOAT) {
							if(analyse.word[1].val==-1)
								add_code(VAR_FLOATING);
							else {
								add_code(VAR_ARRAY_FLOATING);
								if(analyse.word[1].f==0.0f) {
									add_code(ASM_CODE_VAL);
									add_int(analyse.word[1].val);
									}
								else {
									add_code(ASM_CODE_VAR);
									add_short(analyse.word[1].val);
									}
								}
							}
						else if(analyse.word[3].id==CMD_BITMAP) {
							if(analyse.word[1].val==-1)
								add_code(VAR_BITMAP);
							else {
								add_code(VAR_ARRAY_BITMAP);
								if(analyse.word[1].f==0.0f) {
									add_code(ASM_CODE_VAL);
									add_int(analyse.word[1].val);
									}
								else {
									add_code(ASM_CODE_VAR);
									add_short(analyse.word[1].val);
									}
								}
							}
						}
					break;
				case CMD_PUT:
					add_code(ASM_PUT);					break;
				case CMD_GET:
					add_code(ASM_GET);
					add_short(analyse.word[1].id);			// Identifiant de la variable à modifier
					break;
				case CMD_SAVE:
					add_code(ASM_SAVE);					break;
				case CMD_DESTROY:
					add_code(ASM_DESTROY);
					add_short(analyse.word[1].id);			// Identifiant de la variable à modifier
					break;
				case CMD_CREATE:
					add_code(ASM_CREATE);
					add_short(analyse.word[1].id);			// Identifiant de la variable à modifier
					break;
				case CMD_SET_CURRENT_PLAYER:				// Modifie le joueur courant
					add_code(ASM_SET_CURRENT_PLAYER);					break;
				case CMD_CHANGE_UNIT_OWNER:
					add_code(ASM_CHANGE_UNIT_OWNER);					break;
				case CMD_MOVE_UNIT:
					add_code(ASM_MOVE_UNIT);							break;
				case CMD_KILL_UNIT:
					add_code(ASM_KILL_UNIT);							break;
				case CMD_KICK_UNIT:
					add_code(ASM_KICK_UNIT);							break;
				case CMD_PLAY:
					add_code(ASM_PLAY);									break;
				};
				break;
			};
		}

	if(eval_tree)	{	eval_tree->destroy();	delete eval_tree;	}

	for(int i=0;i<nb_define;i++) {
		free(def_name[i]);
		free(def_text[i]);
		}

	fclose(file[0]);
}

int ASM_PROGRAM::run(MAP *map,float dt)									// Execute le script
{
	draw_list.draw(aglfont);			// Execute la liste de commandes de dessin

	if(sleeping) {
		sleep_time-=dt;//(Atimer-last)/((float)SECS_TO_TIMER(1));
//		last=Atimer;
		if(sleep_time<=0.0f)
			sleeping=false;
		if(sleeping) {
			return -2;			// Marque une pause
			}
		}
	if(waiting) {
		if(amx!=mouse_x || amy!=mouse_y || amz!=mouse_z || amb!=mouse_b || keypressed()) {
			waiting=false;
			}
		if(waiting)
			return -3;				// Attend un évènement
		}
	for(int f_cur=0;f_cur<100;f_cur++) {
	if(pos<0 || pos>=size) {
		amx=mouse_x;
		amy=mouse_y;
		amz=mouse_z;
		amb=mouse_b;
		return -1;		// Execution terminée
		}

	byte asm_code=get_byte();		// Lit le code à interpréter
/*	char *code_name[]={"mov","add","sub","mul","div","if","jmp","call","new","inc","dec","push","pop","clear","end","mod","and","or","xor","imp","eqv",
						"not","equal","lequal","gequal","less","greater","nequal","print","logmsg","line","point","triangle","signal","locate","color",
						"cls","box","fillbox","circle","sleep","wait","exp","log","sqrt","cos","sin","rand","abs","tan","cotan","sh","ch","th","coth",
						"acos","asin","atan","ach","ash","ath","mouse_x","mouse_y","mouse_z","mouse_b","get_key","push_var","push_val","int","affect",
						"if_not","next","if_less","push_vars","time","push_vals","put","get","load","save","destroy","create","array_push","array_affect",
						"nb_player","get_unit_number_for_player","get_unit_owner","get_unit_number","annihilated","has_unit","set_current_player","create_unit",
						"change_unit_owner","move_unit","kill_unit","kick_unit","play","map_w","map_h","player_side"};
	printf("code -> %s, %d\n",code_name[asm_code],pos);*/

	switch(asm_code)
	{
	case ASM_ARRAY_AFFECT:	// Affectation (tableaux)
		{
			VAR *v1=stack.pop();
			VAR *v2=&var[get_short()];
			int idx;
			switch(get_byte())
			{
			case ASM_CODE_VAL:
				idx=get_int();
				break;
			case ASM_CODE_VAR:
				{
					int v_id=get_short();
					if(var[v_id].type==VAR_FLOATING)	idx=(int)var[v_id].f;
					else	idx=var[v_id].val;
				}
				break;
			};

			if(v1) {
				switch(v2->type)
				{
				case VAR_ARRAY_INTEGER:
					if(v1->type==VAR_FLOATING)	v1->val=(int)v1->f;
					((int*)v2->s)[idx]=v1->val;
					break;
				case VAR_ARRAY_FLOATING:
					if(v1->type==VAR_INTEGER)	v1->f=v1->val;
					((float*)v2->s)[idx]=v1->f;
					break;
				case VAR_ARRAY_BITMAP:
					if(v1->type==VAR_BITMAP) {
						v1->f=v1->val;
						((BITMAP**)v2->s)[idx]=(BITMAP*)v1->s;
						v1->s=NULL;
						}
					break;
				};
				delete v1;
				}
		}
		break;
	case ASM_AFFECT:	// Affectation
		{
			VAR *v1=stack.pop();
			VAR *v2=&var[get_short()];

			if(v1) {
				v2->destroy();
				*v2=*v1;
				v2->name=NULL;
				if(v2->type==VAR_BITMAP) {
					v1->s=NULL;
					v1->type=VAR_NONE;
					}
				else if(v2->s) {
					v2->s=(byte*) malloc(v2->val);
					if(v2->type==VAR_STRING)
						memcpy(v2->s,v1->s,v2->val+1);
					else
						memcpy(v2->s,v1->s,v2->val);
					}
				delete v1;
				}
		}
		break;
	case ASM_MOV:		// Copie
		{
			VAR *v1,*v2;
			int v1_t=get_byte();
			switch(v1_t)
			{
			case ASM_CODE_VAR:
				v1=&var[get_short()];
				break;
			case ASM_CODE_VAL:
				{
				v1=new VAR;
//				v1->init();
				switch(get_byte())
				{
				case ASM_CODE_INT:
					v1->type=VAR_INTEGER;
					v1->val=get_int();
					break;
				case ASM_CODE_FLT:
					v1->type=VAR_FLOATING;
					v1->f=get_float();
					break;
				case ASM_CODE_STR:
					v1->type=VAR_STRING;
					v1->s=(byte*)get_string(&v1->val);
					break;
				};
				}
				break;
			case ASM_CODE_REG:
				v1=&(reg[get_byte()]);
				break;
			};
			int v2_t=get_byte();
			switch(v2_t)
			{
			case ASM_CODE_VAR:
				v2=&var[get_short()];
				break;
			case ASM_CODE_REG:
				v2=&(reg[get_byte()]);
				break;
			default:
				v2=NULL;
			};
			if(v2) {
				v2->destroy();
				*v2=*v1;
				v2->name=NULL;
				if(v2->type==VAR_BITMAP) {
					v1->s=NULL;
					v1->type=VAR_NONE;
					}
				else if(v2->s) {
					v2->s=(byte*) malloc(v2->val);
					if(v2->type==VAR_STRING)
						memcpy(v2->s,v1->s,v2->val+1);
					else
						memcpy(v2->s,v1->s,v2->val);
					}
				}
			if(v1_t==ASM_CODE_VAL) {
//				v1->destroy();
				delete v1;
				}
		}
		break;
	case ASM_ADD:					// Addition
		{
			VAR *v1,*v2;
			v1=stack.pop();
			v2=stack.pop();
			if(v1->type!=v2->type) {
				if(v1->type==VAR_INTEGER && v2->type==VAR_FLOATING) {
					v1->type=VAR_FLOATING;
					v1->f=v1->val;
					}
				else if(v2->type==VAR_INTEGER && v1->type==VAR_FLOATING) {
					v2->type=VAR_FLOATING;
					v2->f=v2->val;
					}
				}
			switch(v1->type)
			{
			case VAR_INTEGER:
				v1->val+=v2->val;
				break;
			case VAR_FLOATING:
				v1->f+=v2->f;
				break;
			case VAR_STRING:
				{
					byte *tmp=(byte*) malloc(v1->val+v2->val+1);
					memcpy(tmp,v2->s,v2->val);
					memcpy(tmp+v2->val,v1->s,v1->val+1);
					free(v1->s);
					v1->val+=v2->val;
					v1->s=tmp;
				}
				break;
			};
			stack.c_push(v1);
			delete v2;
		}
		break;
	case ASM_SUB:				// Soustraction
		{
			VAR *v1,*v2;
			v1=stack.pop();
			v2=stack.pop();
			if(v1->type!=v2->type) {
				if(v1->type==VAR_INTEGER && v2->type==VAR_FLOATING) {
					v1->type=VAR_FLOATING;
					v1->f=v1->val;
					}
				else if(v2->type==VAR_INTEGER && v1->type==VAR_FLOATING) {
					v2->type=VAR_FLOATING;
					v2->f=v2->val;
					}
				}
			switch(v1->type)
			{
			case VAR_INTEGER:
				v2->val-=v1->val;
				break;
			case VAR_FLOATING:
				v2->f-=v1->f;
				break;
			};
			stack.c_push(v2);
			delete v1;
		}
		break;
	case ASM_MUL:
		{
			VAR *v1,*v2;
			v1=stack.pop();
			v2=stack.pop();
			if(v1->type!=v2->type) {
				if(v1->type==VAR_INTEGER && v2->type==VAR_FLOATING) {
					v1->type=VAR_FLOATING;
					v1->f=v1->val;
					}
				else if(v2->type==VAR_INTEGER && v1->type==VAR_FLOATING) {
					v2->type=VAR_FLOATING;
					v2->f=v2->val;
					}
				}
			switch(v1->type)
			{
			case VAR_INTEGER:
				v2->val*=v1->val;
				break;
			case VAR_FLOATING:
				v2->f*=v1->f;
				break;
			};
			stack.c_push(v2);
			delete v1;
		}
		break;
	case ASM_DIV:
		{
			VAR *v1,*v2;
			v1=stack.pop();
			v2=stack.pop();
			if(v1->type!=v2->type) {
				if(v1->type==VAR_INTEGER && v2->type==VAR_FLOATING) {
					v1->type=VAR_FLOATING;
					v1->f=v1->val;
					}
				else if(v2->type==VAR_INTEGER && v1->type==VAR_FLOATING) {
					v2->type=VAR_FLOATING;
					v2->f=v2->val;
					}
				}
			switch(v1->type)
			{
			case VAR_INTEGER:
				v2->val/=v1->val;
				break;
			case VAR_FLOATING:
				v2->f/=v1->f;
				break;
			};
			stack.c_push(v2);
			delete v1;
		}
		break;
	case ASM_IF:
		{
			VAR *v=stack.pop();
			int target_pos=get_int();		// Cible du saut en cas de succès du test
			if((v->type==VAR_INTEGER && v->val!=0) || (v->type==VAR_FLOATING && v->f!=0.0f) || (v->type==VAR_BITMAP && v->s!=NULL))				// test
				pos=target_pos;			// saute si test positif
			delete v;
		}
		break;
	case ASM_IF_LESS:
		{
			VAR *v2=stack.pop();
			VAR *v1=stack.pop();
			int target_pos=get_int();		// Cible du saut en cas de succès du test
			if(v1->type==v2->type) {
				if((v1->type==VAR_INTEGER && v1->val<v2->val) || (v1->type==VAR_FLOATING && v1->f<v2->f))				// test
					pos=target_pos;			// saute si test positif
				}
			else if(v1->type==VAR_INTEGER && v2->type==VAR_FLOATING && v1->val<v2->f)
				pos=target_pos;			// saute si test positif
			else if(v1->type==VAR_FLOATING && v2->type==VAR_INTEGER && v1->f<v2->val)
				pos=target_pos;			// saute si test positif
//			v1->destroy();
//			v2->destroy();
			delete v1;
			delete v2;
		}
		break;
	case ASM_IF_NOT:
		{
			VAR *v=stack.pop();
			int target_pos=get_int();		// Cible du saut en cas de succès du test
			if((v->type==VAR_INTEGER && v->val==0) || (v->type==VAR_FLOATING && v->f==0.0f) || (v->type==VAR_BITMAP && v->s==NULL))				// test
				pos=target_pos;			// saute si test positif
//			v->destroy();
			delete v;
		}
		break;
	case ASM_JMP:		pos=get_int();			break;		// Transfère l'éxécution à une position donnée
	case ASM_CALL:								break;
	case ASM_NEW:
		{
			int v_id=get_short();			// Variable à créer
			var[v_id].destroy();			// On commence par la détruire
			var[v_id].init();
			var[v_id].type=get_byte();
			switch(var[v_id].type)
			{
			case VAR_INTEGER:
				var[v_id].val=0;
				break;
			case VAR_FLOATING:
				var[v_id].f=0.0f;
				break;
			case VAR_BITMAP:
				var[v_id].s=NULL;
				break;
			case VAR_ARRAY_INTEGER:
				{
					int idx;
					switch(get_byte())
					{
					case ASM_CODE_VAL:
						idx=get_int();
						break;
					case ASM_CODE_VAR:
						{
							int v_id=get_short();
							if(var[v_id].type==VAR_FLOATING)	idx=(int)var[v_id].f;
							else	idx=var[v_id].val;
						}
						break;
					};
					var[v_id].val=idx;		// Lit la taille du tableau
					var[v_id].s=(byte*) malloc(sizeof(int)*var[v_id].val);
				}
				break;
			case VAR_ARRAY_FLOATING:
				{
					int idx;
					switch(get_byte())
					{
					case ASM_CODE_VAL:
						idx=get_int();
						break;
					case ASM_CODE_VAR:
						{
							int v_id=get_short();
							if(var[v_id].type==VAR_FLOATING)	idx=(int)var[v_id].f;
							else	idx=var[v_id].val;
						}
						break;
					};
					var[v_id].val=idx;		// Lit la taille du tableau
					var[v_id].s=(byte*) malloc(sizeof(float)*var[v_id].val);
				}
				break;
			case VAR_ARRAY_BITMAP:
				{
					int idx;
					switch(get_byte())
					{
					case ASM_CODE_VAL:
						idx=get_int();
						break;
					case ASM_CODE_VAR:
						{
							int v_id=get_short();
							if(var[v_id].type==VAR_FLOATING)	idx=(int)var[v_id].f;
							else	idx=var[v_id].val;
						}
						break;
					};
					var[v_id].val=idx;		// Lit la taille du tableau
					var[v_id].s=(byte*) malloc(sizeof(BITMAP*)*var[v_id].val);
				}
				break;
			};
		}
		break;
	case ASM_INC:
		{
			int	v=get_short();
			if(var[v].type==VAR_INTEGER)	var[v].val++;
			else if(var[v].type==VAR_FLOATING)	var[v].f++;
		}
		break;
	case ASM_NEXT:
		{
			int	v=get_short();
			if(var[v].type==VAR_INTEGER)	var[v].val++;
			else if(var[v].type==VAR_FLOATING)	var[v].f++;
			pos=get_int();
		}
		break;
	case ASM_DEC:
		{
			int	v=get_short();
			if(var[v].type==VAR_INTEGER)	var[v].val--;
			else if(var[v].type==VAR_FLOATING)	var[v].f--;
		}
		break;
	case ASM_PUSH:		stack.push(reg);		break;
	case ASM_ARRAY_PUSH:
		{
			VAR *v1=&var[get_short()];
			VAR *v2=new VAR;
			int idx;
			switch(get_byte())
			{
			case ASM_CODE_VAL:
				idx=get_int();
				break;
			case ASM_CODE_VAR:
				{
					int v_id=get_short();
					if(var[v_id].type==VAR_FLOATING)	idx=(int)var[v_id].f;
					else	idx=var[v_id].val;
				}
				break;
			};
			switch(v1->type)
			{
			case VAR_ARRAY_INTEGER:
				v2->type=VAR_INTEGER;
				v2->val=((int*)v1->s)[idx];
				break;
			case VAR_ARRAY_FLOATING:
				v2->type=VAR_FLOATING;
				v2->f=((float*)v1->s)[idx];
				break;
			};
			stack.c_push(v2);
		}
		break;
	case ASM_PUSH_VAR:
		stack.push(&var[get_short()]);
		break;
	case ASM_PUSH_VARS:				// Empile nb variables
		{
			int nb=get_short();
			for(int i=0;i<nb;i++)
				stack.push(&var[get_short()]);
		}
		break;
	case ASM_PUSH_VAL:
		{
			VAR *v1;
			v1=new VAR;
			switch(get_byte())
			{
			case ASM_CODE_INT:
				v1->type=VAR_INTEGER;
				v1->val=get_int();
				break;
			case ASM_CODE_FLT:
				v1->type=VAR_FLOATING;
				v1->f=get_float();
				break;
			case ASM_CODE_STR:
				v1->type=VAR_STRING;
				v1->s=(byte*)get_string(&v1->val);
				break;
			};
			stack.c_push(v1);
		}
		break;
	case ASM_PUSH_VALS:				// Empile nb variables
		{
			int nb=get_short();
			for(int i=0;i<nb;i++) {
				VAR *v1;
				v1=new VAR;
				switch(get_byte())
				{
				case ASM_CODE_INT:
					v1->type=VAR_INTEGER;
					v1->val=get_int();
					break;
				case ASM_CODE_FLT:
					v1->type=VAR_FLOATING;
					v1->f=get_float();
					break;
				case ASM_CODE_STR:
					v1->type=VAR_STRING;
					v1->s=(byte*)get_string(&v1->val);
					break;
				};
				stack.c_push(v1);
				}
		}
		break;
	case ASM_POP:
		{
			VAR *v=stack.pop();
			reg[0].destroy();
			reg[0]=*v;
			if(v->type==VAR_BITMAP || v->type==VAR_STRING) {
				v->s=NULL;
				v->type=VAR_NONE;
				}
			delete v;
		}
		break;
	case ASM_CLEAR:		stack.destroy();		break;
	case ASM_END:		pos=-1;					break;			// Met fin au programme
	case ASM_MOD:
		{
			VAR *v1,*v2;
			v1=stack.pop();
			v2=stack.pop();
			switch(v1->type)
			{
			case VAR_INTEGER:
				v2->val=v2->val%v1->val;
				break;
			};
			stack.c_push(v2);
//			v1->destroy();
//			v2->destroy();
			delete v1;
//			delete v2;
		}
		break;
	case ASM_AND:
		{
			VAR *v1,*v2;
			v1=stack.pop();
			v2=stack.pop();
			switch(v1->type)
			{
			case VAR_INTEGER:
				v2->val&=v1->val;
				break;
			};
			stack.c_push(v2);
//			v1->destroy();
//			v2->destroy();
			delete v1;
//			delete v2;
		}
		break;
	case ASM_OR:
		{
			VAR *v1,*v2;
			v1=stack.pop();
			v2=stack.pop();
			if(v2->type==VAR_FLOATING)
				v2->val=(int)v2->f;
			switch(v1->type)
			{
			case VAR_INTEGER:
				v2->val=(v1->val | v2->val);
				v2->type=VAR_INTEGER;
				break;
			};
			stack.c_push(v2);
//			v1->destroy();
//			v2->destroy();
			delete v1;
//			delete v2;
		}
		break;
	case ASM_XOR:
		{
			VAR *v1,*v2;
			v1=stack.pop();
			v2=stack.pop();
			switch(v1->type)
			{
			case VAR_INTEGER:
				v2->val=v2->val ^ v1->val;
				break;
			};
			stack.c_push(v2);
//			v1->destroy();
//			v2->destroy();
			delete v1;
//			delete v2;
		}
		break;
	case ASM_IMP:
		{
			VAR *v1,*v2;
			v1=stack.pop();
			v2=stack.pop();
			switch(v1->type)
			{
			case VAR_INTEGER:
				v2->val=~((~v2->val)|(v2->val&v1->val));
				break;
			};
			stack.c_push(v2);
//			v1->destroy();
//			v2->destroy();
			delete v1;
//			delete v2;
		}
		break;
	case ASM_EQV:
		{
			VAR *v1,*v2;
			v1=stack.pop();
			v2=stack.pop();
			switch(v1->type)
			{
			case VAR_INTEGER:
				v2->val=(v2->val&v1->val)|((~v2->val)&&(~v1->val));
				break;
			};
			stack.c_push(v2);
//			v1->destroy();
//			v2->destroy();
			delete v1;
//			delete v2;
		}
		break;
	case ASM_NOT:
		{
			VAR *v1;
			v1=stack.pop();
			switch(v1->type)
			{
			case VAR_INTEGER:
				v1->val=(not v1->val);
				break;
			case VAR_FLOATING:
				v1->f= (v1->f==0.0f) ? 1.0f : 0.0f;
				break;
			};
			stack.c_push(v1);
//			v1->destroy();
//			delete v1;
		}
		break;
	case ASM_EQUAL:
		{
			VAR *v1,*v2;
			v1=stack.pop();
			v2=stack.pop();
			if(v1->type!=v2->type) {
				if(v1->type==VAR_FLOATING && v2->type==VAR_INTEGER)		v2->f=v2->val;
				else if(v1->type==VAR_INTEGER && v2->type==VAR_FLOATING) {
					v1->f=v1->val;
					v1->type=VAR_FLOATING;
					}
				}
			switch(v1->type)
			{
			case VAR_BITMAP:
				v2->val=(v2->s==v1->s);
				v2->type=VAR_INTEGER;
				v2->s=NULL;
				v1->s=NULL;
				v1->type=VAR_NONE;
				break;
			case VAR_NONE:
				v2->val=0;
				v2->type=VAR_INTEGER;
				break;
			case VAR_INTEGER:
				v2->val=(v2->val==v1->val);
				v2->type=VAR_INTEGER;
				break;
			case VAR_FLOATING:
				v2->val=(v2->f==v1->f);
				v2->type=VAR_INTEGER;
				break;
			case VAR_STRING:
				if(v1->val==v2->val) {
					v2->val=strcmp((char*)v1->s,(char*)v2->s)==0 ? 1 : 0;
					free(v2->s);
					v2->s=NULL;
					v2->type=VAR_INTEGER;
					}
				else {
					free(v2->s);
					v2->s=NULL;
					v2->val=0;
					v2->type=VAR_INTEGER;
					}
				break;
			};
			stack.c_push(v2);
//			v1->destroy();
//			v2->destroy();
			delete v1;
//			delete v2;
		}
		break;
	case ASM_LEQUAL:
		{
			VAR *v1,*v2;
			v1=stack.pop();
			v2=stack.pop();
			if(v1->type!=v2->type) {
				if(v1->type==VAR_FLOATING && v2->type==VAR_INTEGER)		v2->f=v2->val;
				else if(v1->type==VAR_INTEGER && v2->type==VAR_FLOATING) {
					v1->f=v1->val;
					v1->type=VAR_FLOATING;
					}
				}
			switch(v1->type)
			{
			case VAR_NONE:
				v2->val=0;
				v2->type=VAR_INTEGER;
				break;
			case VAR_INTEGER:
				v2->val=(v2->val<=v1->val);
				v2->type=VAR_INTEGER;
				break;
			case VAR_FLOATING:
				v2->val=(v2->f<=v1->f);
				v2->type=VAR_INTEGER;
				break;
			case VAR_STRING:
				if(v1->val==v2->val) {
					v2->val=strcmp((char*)v2->s,(char*)v1->s)==1 ? 0 : 1;
					v2->type=VAR_INTEGER;
					free(v2->s);
					v2->s=NULL;
					}
				else {
					free(v2->s);
					v2->s=NULL;
					v2->val=0;
					v2->type=VAR_INTEGER;
					}
				break;
			};
			stack.c_push(v2);
//			v1->destroy();
//			v2->destroy();
			delete v1;
//			delete v2;
		}
		break;
	case ASM_GEQUAL:
		{
			VAR *v1,*v2;
			v1=stack.pop();
			v2=stack.pop();
			if(v1->type!=v2->type) {
				if(v1->type==VAR_FLOATING && v2->type==VAR_INTEGER)		v2->f=v2->val;
				else if(v1->type==VAR_INTEGER && v2->type==VAR_FLOATING) {
					v1->f=v1->val;
					v1->type=VAR_FLOATING;
					}
				}
			switch(v1->type)
			{
			case VAR_NONE:
				v2->val=0;
				v2->type=VAR_INTEGER;
				break;
			case VAR_INTEGER:
				v2->val=(v2->val>=v1->val);
				v2->type=VAR_INTEGER;
				break;
			case VAR_FLOATING:
				v2->val=(v2->f>=v1->f);
				v2->type=VAR_INTEGER;
				break;
			case VAR_STRING:
				if(v1->val==v2->val) {
					v2->val=strcmp((char*)v2->s,(char*)v1->s)==-1 ? 0 : 1;
					free(v2->s);
					v2->s=NULL;
					v2->type=VAR_INTEGER;
					}
				else {
					free(v2->s);
					v2->s=NULL;
					v2->val=0;
					v2->type=VAR_INTEGER;
					}
				break;
			};
			stack.c_push(v2);
//			v1->destroy();
//			v2->destroy();
			delete v1;
//			delete v2;
		}
		break;
	case ASM_LESS:
		{
			VAR *v1,*v2;
			v1=stack.pop();
			v2=stack.pop();
			if(v1->type!=v2->type) {
				if(v1->type==VAR_FLOATING && v2->type==VAR_INTEGER)		v2->f=v2->val;
				else if(v1->type==VAR_INTEGER && v2->type==VAR_FLOATING) {
					v1->f=v1->val;
					v1->type=VAR_FLOATING;
					}
				}
			switch(v1->type)
			{
			case VAR_NONE:
				v2->val=0;
				v2->type=VAR_INTEGER;
				break;
			case VAR_INTEGER:
				v2->val=(v2->val<v1->val) ? 1 : 0;
				v2->type=VAR_INTEGER;
				break;
			case VAR_FLOATING:
				v2->val=(v2->f<v1->f) ? 1 : 0;
				v2->type=VAR_INTEGER;
				break;
			case VAR_STRING:
				if(v1->val==v2->val) {
					v2->val=strcmp((char*)v2->s,(char*)v1->s)==-1 ? 1 : 0;
					free(v2->s);
					v2->s=NULL;
					v2->type=VAR_INTEGER;
					}
				else {
					free(v2->s);
					v2->s=NULL;
					v2->val=0;
					v2->type=VAR_INTEGER;
					}
				break;
			};
			stack.c_push(v2);
//			v1->destroy();
//			v2->destroy();
			delete v1;
//			delete v2;
		}
		break;
	case ASM_GREATER:
		{
			VAR *v1,*v2;
			v1=stack.pop();
			v2=stack.pop();
			if(v1->type!=v2->type) {
				if(v1->type==VAR_FLOATING && v2->type==VAR_INTEGER)		v2->f=v2->val;
				else if(v1->type==VAR_INTEGER && v2->type==VAR_FLOATING) {
					v1->f=v1->val;
					v1->type=VAR_FLOATING;
					}
				}
			switch(v1->type)
			{
			case VAR_NONE:
				v2->val=0;
				v2->type=VAR_INTEGER;
				break;
			case VAR_INTEGER:
				v2->val=(v2->val>v1->val);
				v2->type=VAR_INTEGER;
				break;
			case VAR_FLOATING:
				v2->val=(v2->f>v1->f);
				v2->type=VAR_INTEGER;
				break;
			case VAR_STRING:
				if(v1->val==v2->val) {
					v2->val=strcmp((char*)v2->s,(char*)v1->s)==1 ? 1 : 0;
					free(v2->s);
					v2->s=NULL;
					v2->type=VAR_INTEGER;
					}
				else {
					free(v2->s);
					v2->s=NULL;
					v2->val=0;
					v2->type=VAR_INTEGER;
					}
				break;
			};
			stack.c_push(v2);
//			v1->destroy();
//			v2->destroy();
			delete v1;
//			delete v2;
		}
		break;
	case ASM_NEQUAL:
		{
			VAR *v1,*v2;
			v1=stack.pop();
			v2=stack.pop();
			if(v1->type!=v2->type) {
				if(v1->type==VAR_FLOATING && v2->type==VAR_INTEGER)		v2->f=v2->val;
				else if(v1->type==VAR_INTEGER && v2->type==VAR_FLOATING) {
					v1->f=v1->val;
					v1->type=VAR_FLOATING;
					}
				}
			switch(v1->type)
			{
			case VAR_BITMAP:
				v2->val=(v2->s!=v1->s);
				v2->type=VAR_INTEGER;
				v2->s=NULL;
				v1->s=NULL;
				v1->type=VAR_NONE;
				break;
			case VAR_NONE:
				v2->val=0;
				v2->type=VAR_INTEGER;
				break;
			case VAR_INTEGER:
				v2->val=(v2->val!=v1->val);
				v2->type=VAR_INTEGER;
				break;
			case VAR_FLOATING:
				v2->val=(v2->f!=v1->f);
				v2->type=VAR_INTEGER;
				break;
			case VAR_STRING:
				if(v1->val==v2->val) {
					v2->val=strcmp((char*)v2->s,(char*)v1->s)==0 ? 0 : 1;
					free(v2->s);
					v2->s=NULL;
					v2->type=VAR_INTEGER;
					}
				else {
					free(v2->s);
					v2->val=0;
					v2->s=NULL;
					v2->type=VAR_INTEGER;
					}
				break;
			};
			stack.c_push(v2);
//			v1->destroy();
//			v2->destroy();
			delete v1;
//			delete v2;
		}
		break;
	case ASM_LOCATE:
		{
			VAR *v1=stack.pop();
			VAR *v2=stack.pop();

			if(v1->type==VAR_FLOATING)	v1->val=(int)v1->f;
			if(v2->type==VAR_FLOATING)	v2->val=(int)v2->f;
			tx=v1->val;
			ty=v2->val;
//			v1->destroy();
//			v2->destroy();
			delete v1;
			delete v2;
		}
		break;
	case ASM_COLOR:
		{
			VAR *v1=stack.pop();
			VAR *v2=stack.pop();
			if(v2) {
				if(v1->type==VAR_FLOATING)	v1->val=(int)v1->f;
				tbcol=v1->val;
//				v1->destroy();
				delete v1;
				if(v2->type==VAR_FLOATING)	v2->val=(int)v2->f;
				tcol=v2->val;
//				v2->destroy();
				delete v2;
				}
			else {
				if(v1->type==VAR_FLOATING)	v1->val=(int)v1->f;
				tcol=v1->val;
//				v1->destroy();
				delete v1;
				}
		}
		break;
	case ASM_PRINT:
		{
			VAR *v1;
			STACK inv;
			while(v1=stack.pop()) {
				inv.c_push(v1);
//				v1->destroy();
//				delete v1;
				}
			while(v1=inv.pop()) {
				switch(v1->type)
				{
				case VAR_INTEGER:
					{
						DRAW_OBJECT draw_obj;
						draw_obj.type=DRAW_TYPE_TEXT;
						draw_obj.r[0]=1.0f;
						draw_obj.g[0]=1.0f;
						draw_obj.b[0]=1.0f;
						draw_obj.x[0]=tx;
						draw_obj.y[0]=ty;
						draw_obj.text=(char*) malloc(20);
						usprintf(draw_obj.text,"%d",v1->val);
						draw_list.add(draw_obj);
						tx+=(int)(uszprintf(tmp_buf,100,"%d",v1->val)*8.8888f);
					}
					break;
				case VAR_FLOATING:
					{
						DRAW_OBJECT draw_obj;
						draw_obj.type=DRAW_TYPE_TEXT;
						draw_obj.r[0]=1.0f;
						draw_obj.g[0]=1.0f;
						draw_obj.b[0]=1.0f;
						draw_obj.x[0]=tx;
						draw_obj.y[0]=ty;
						draw_obj.text=(char*)malloc(20);
						usprintf(draw_obj.text,"%f",v1->f);
						draw_list.add(draw_obj);
						tx+=(int)(uszprintf(tmp_buf,100,"%f",v1->f)*8.8888f);
					}
					break;
				case VAR_STRING:
					{
						DRAW_OBJECT draw_obj;
						draw_obj.type=DRAW_TYPE_TEXT;
						draw_obj.r[0]=1.0f;
						draw_obj.g[0]=1.0f;
						draw_obj.b[0]=1.0f;
						draw_obj.x[0]=tx;
						draw_obj.y[0]=ty;
						draw_obj.text=strdup((const char*)v1->s);
						draw_list.add(draw_obj);
						tx+=(int)(strlen((char*)v1->s)*8.8888f);;
					}
					break;
				};
//				v1->destroy();
				delete v1;
				}
			inv.destroy();
			tx=0;
			ty+=8;
		}
		break;
	case ASM_LOGMSG:
		{
			VAR *v1;
			STACK inv;
			char tmp[10000];
			char buf[1000];
			tmp[0]=0;
			while(v1=stack.pop()) {
				inv.c_push(v1);
				}
			while(v1=inv.pop()) {
				switch(v1->type)
				{
				case VAR_INTEGER:
					usprintf(buf,"%d",v1->val);
					strcat(tmp,buf);
					break;
				case VAR_FLOATING:
					usprintf(buf,"%f",v1->f);
					strcat(tmp,buf);
					break;
				case VAR_STRING:
					if(v1->s!=NULL)
						usprintf(buf,"%s",v1->s);
					strcat(tmp,buf);
					break;
				};
				delete v1;
				}
			Console->AddEntry(tmp);
			inv.destroy();
		}
		break;
	case ASM_BOX:
		{
			VAR *v[5];
			for(int i=4;i>=0;i--) {
				v[i]=stack.pop();
				if(v[i]->type==VAR_FLOATING)	v[i]->val=(int)v[i]->f;
				}
			DRAW_OBJECT draw_object;
			draw_object.type=DRAW_TYPE_BOX;
			draw_object.r[0]=((v[4]->val>>16)&0xFF)/255.0f;
			draw_object.g[0]=((v[4]->val>>8)&0xFF)/255.0f;
			draw_object.b[0]=(v[4]->val&0xFF)/255.0f;
			draw_object.x[0]=v[0]->val;
			draw_object.x[1]=v[2]->val;
			draw_object.y[0]=v[1]->val;
			draw_object.y[1]=v[3]->val;
			draw_list.add(draw_object);
			for(int i=0;i<5;i++)
				delete v[i];
		}
		break;
	case ASM_FILLBOX:
		{
			VAR *v[5];
			for(int i=4;i>=0;i--) {
				v[i]=stack.pop();
				if(v[i]->type==VAR_FLOATING)	v[i]->val=(int)v[i]->f;
				}
			DRAW_OBJECT draw_object;			
			draw_object.type=DRAW_TYPE_FILLBOX;
			draw_object.r[0]=((v[4]->val>>16)&0xFF)/255.0f;
			draw_object.g[0]=((v[4]->val>>8)&0xFF)/255.0f;
			draw_object.b[0]=(v[4]->val&0xFF)/255.0f;
			draw_object.x[0]=v[0]->val;
			draw_object.x[1]=v[2]->val;
			draw_object.y[0]=v[1]->val;
			draw_object.y[1]=v[3]->val;
			draw_list.add(draw_object);
			for(int i=0;i<5;i++)
				delete v[i];
		}
		break;
	case ASM_LINE:
		{
			VAR *v[5];
			for(int i=4;i>=0;i--) {
				v[i]=stack.pop();
				if(v[i]->type==VAR_FLOATING)	v[i]->val=(int)v[i]->f;
				}
			DRAW_OBJECT draw_object;			
			draw_object.type=DRAW_TYPE_LINE;
			draw_object.r[0]=((v[4]->val>>16)&0xFF)/255.0f;
			draw_object.g[0]=((v[4]->val>>8)&0xFF)/255.0f;
			draw_object.b[0]=(v[4]->val&0xFF)/255.0f;
			draw_object.x[0]=v[0]->val;
			draw_object.x[1]=v[2]->val;
			draw_object.y[0]=v[1]->val;
			draw_object.y[1]=v[3]->val;
			draw_list.add(draw_object);
			for(int i=0;i<5;i++)
				delete v[i];
		}
		break;
	case ASM_TRIANGLE:
		{
			VAR *v[7];
			for(int i=6;i>=0;i--) {
				v[i]=stack.pop();
				if(v[i]->type==VAR_FLOATING)	v[i]->val=(int)v[i]->f;
				}
			DRAW_OBJECT draw_object;			
			draw_object.type=DRAW_TYPE_TRIANGLE;
			draw_object.r[0]=((v[6]->val>>16)&0xFF)/255.0f;
			draw_object.g[0]=((v[6]->val>>8)&0xFF)/255.0f;
			draw_object.b[0]=(v[6]->val&0xFF)/255.0f;
			draw_object.x[0]=v[0]->val;
			draw_object.x[1]=v[2]->val;
			draw_object.x[2]=v[4]->val;
			draw_object.y[0]=v[1]->val;
			draw_object.y[1]=v[3]->val;
			draw_object.y[2]=v[5]->val;
			draw_list.add(draw_object);
			for(int i=0;i<7;i++)
				delete v[i];
		}
		break;
	case ASM_POINT:
		{
			VAR *v[3];
			for(int i=2;i>=0;i--) {
				v[i]=stack.pop();
				if(v[i]->type==VAR_FLOATING)	v[i]->val=(int)v[i]->f;
				}
			DRAW_OBJECT draw_object;			
			draw_object.type=DRAW_TYPE_POINT;
			draw_object.r[0]=((v[2]->val>>16)&0xFF)/255.0f;
			draw_object.g[0]=((v[2]->val>>8)&0xFF)/255.0f;
			draw_object.b[0]=(v[2]->val&0xFF)/255.0f;
			draw_object.x[0]=v[0]->val;
			draw_object.y[0]=v[1]->val;
			draw_list.add(draw_object);
			for(int i=0;i<3;i++)
				delete v[i];
		}
		break;
	case ASM_SIGNAL:
		{
			VAR *v=stack.pop();
			if(v->type==VAR_FLOATING)	v->val=(int)v->f;
			int signal=v->val;
			delete v;
			return signal;
		}
		break;
	case ASM_CLS:
		draw_list.destroy();
		break;
	case ASM_CIRCLE:
		{
			VAR *v[4];
			for(int i=3;i>=0;i--) {
				v[i]=stack.pop();
				if(v[i]->type==VAR_FLOATING)	v[i]->val=(int)v[i]->f;
				}

			DRAW_OBJECT draw_object;			
			draw_object.type=DRAW_TYPE_CIRCLE;
			draw_object.r[0]=((v[3]->val>>16)&0xFF)/255.0f;
			draw_object.g[0]=((v[3]->val>>8)&0xFF)/255.0f;
			draw_object.b[0]=(v[3]->val&0xFF)/255.0f;
			draw_object.x[0]=v[0]->val;
			draw_object.y[0]=v[1]->val;
			draw_object.r[1]=v[2]->val;
			glBegin(GL_LINE_STRIP);
				glColor3f(((v[3]->val>>16)&0xFF)/255.0f,((v[3]->val>>8)&0xFF)/255.0f,(v[3]->val&0xFF)/255.0f);
				{
					int max = (int)(sqrt(v[2]->val)*2.0f)*2;
					if(max>0)
						for(int i=0;i<=v[2]->val*10;i++)
							glVertex2f(v[0]->val+v[2]->val*cos(i*6.2831853072f/max),v[1]->val+v[2]->val*sin(i*6.2831853072f/max));
				}
			glEnd();
			for(int i=0;i<4;i++)
				delete v[i];
		}
		break;
	case ASM_SLEEP:
		{
			VAR *v=stack.pop();
			if(v) {
				if(v->type==VAR_INTEGER)	v->f=v->val;
				sleeping=true;
				sleep_time=v->f;
				f_cur=1000;
//				last=Atimer;
//				v->destroy();
				delete v;
				}
			else {
				clear_keybuf();
				waiting=true;
				}
		}
		break;
	case ASM_WAIT:
		waiting=true;
		break;
	case ASM_EXP:
		{
			VAR *v1;
			v1=stack.pop();
			switch(v1->type)
			{
			case VAR_INTEGER:
				v1->f=exp(v1->val);
				v1->type=VAR_FLOATING;
				break;
			case VAR_FLOATING:
				v1->f=exp(v1->f);
				break;
			};
			stack.c_push(v1);
//			v1->destroy();
//			delete v1;
		}
		break;
	case ASM_LOG:
		{
			VAR *v1;
			v1=stack.pop();
			switch(v1->type)
			{
			case VAR_INTEGER:
				v1->f=log(v1->val);
				v1->type=VAR_FLOATING;
				break;
			case VAR_FLOATING:
				v1->f=log(v1->f);
				break;
			};
			stack.c_push(v1);
//			v1->destroy();
//			delete v1;
		}
		break;
	case ASM_SQRT:
		{
			VAR *v1;
			v1=stack.pop();
			switch(v1->type)
			{
			case VAR_INTEGER:
				v1->f=sqrt(v1->val);
				v1->type=VAR_FLOATING;
				break;
			case VAR_FLOATING:
				v1->f=sqrt(v1->f);
				break;
			};
			stack.c_push(v1);
//			v1->destroy();
//			delete v1;
		}
		break;
	case ASM_COS:
		{
			VAR *v1;
			v1=stack.pop();
			switch(v1->type)
			{
			case VAR_INTEGER:
				v1->f=cos(v1->val);
				v1->type=VAR_FLOATING;
				break;
			case VAR_FLOATING:
				v1->f=cos(v1->f);
				break;
			};
			stack.c_push(v1);
//			v1->destroy();
//			delete v1;
		}
		break;
	case ASM_SIN:
		{
			VAR *v1;
			v1=stack.pop();
			switch(v1->type)
			{
			case VAR_INTEGER:
				v1->f=sin(v1->val);
				v1->type=VAR_FLOATING;
				break;
			case VAR_FLOATING:
				v1->f=sin(v1->f);
				break;
			};
			stack.c_push(v1);
//			v1->destroy();
//			delete v1;
		}
		break;
	case ASM_RAND:
		{
			VAR *v1;
			v1=stack.pop();
			switch(v1->type)
			{
			case VAR_INTEGER:
				v1->val=rand()%v1->val;
				break;
			case VAR_FLOATING:
				v1->val=rand()%((int)v1->f);
				v1->type=VAR_INTEGER;
				break;
			};
			stack.c_push(v1);
//			v1->destroy();
//			delete v1;
		}
		break;
	case ASM_ABS:
		{
			VAR *v1;
			v1=stack.pop();
			switch(v1->type)
			{
			case VAR_INTEGER:
				v1->val=abs(v1->val);
				break;
			case VAR_FLOATING:
				v1->f=fabs(v1->f);
				break;
			};
			stack.c_push(v1);
//			v1->destroy();
//			delete v1;
		}
		break;
	case ASM_TAN:
		{
			VAR *v1;
			v1=stack.pop();
			switch(v1->type)
			{
			case VAR_INTEGER:
				v1->f=tan(v1->val);
				v1->type=VAR_FLOATING;
				break;
			case VAR_FLOATING:
				v1->f=tan(v1->f);
				break;
			};
			stack.c_push(v1);
//			v1->destroy();
//			delete v1;
		}
		break;
	case ASM_COTAN:
		{
			VAR *v1;
			v1=stack.pop();
			switch(v1->type)
			{
			case VAR_INTEGER:
				v1->f=1.0f/tan(v1->val);
				v1->type=VAR_FLOATING;
				break;
			case VAR_FLOATING:
				v1->f=1.0f/tan(v1->f);
				break;
			};
			stack.c_push(v1);
//			v1->destroy();
//			delete v1;
		}
		break;
	case ASM_CH:
		{
			VAR *v1;
			v1=stack.pop();
			switch(v1->type)
			{
			case VAR_INTEGER:
				v1->f=cosh(v1->val);
				v1->type=VAR_FLOATING;
				break;
			case VAR_FLOATING:
				v1->f=cosh(v1->f);
				break;
			};
			stack.c_push(v1);
//			v1->destroy();
//			delete v1;
		}
		break;
	case ASM_SH:
		{
			VAR *v1;
			v1=stack.pop();
			switch(v1->type)
			{
			case VAR_INTEGER:
				v1->f=sinh(v1->val);
				v1->type=VAR_FLOATING;
				break;
			case VAR_FLOATING:
				v1->f=sinh(v1->f);
				break;
			};
			stack.c_push(v1);
//			v1->destroy();
//			delete v1;
		}
		break;
	case ASM_ACOS:
		{
			VAR *v1;
			v1=stack.pop();
			switch(v1->type)
			{
			case VAR_INTEGER:
				v1->f=acos(v1->val);
				v1->type=VAR_FLOATING;
				break;
			case VAR_FLOATING:
				v1->f=acos(v1->f);
				break;
			};
			stack.c_push(v1);
//			v1->destroy();
//			delete v1;
		}
		break;
	case ASM_ASIN:
		{
			VAR *v1;
			v1=stack.pop();
			switch(v1->type)
			{
			case VAR_INTEGER:
				v1->f=asin(v1->val);
				v1->type=VAR_FLOATING;
				break;
			case VAR_FLOATING:
				v1->f=asin(v1->f);
				break;
			};
			stack.c_push(v1);
//			v1->destroy();
//			delete v1;
		}
		break;
	case ASM_ATAN:
		{
			VAR *v1;
			v1=stack.pop();
			switch(v1->type)
			{
			case VAR_INTEGER:
				v1->f=atan(v1->val);
				v1->type=VAR_FLOATING;
				break;
			case VAR_FLOATING:
				v1->f=atan(v1->f);
				break;
			};
			stack.c_push(v1);
//			v1->destroy();
//			delete v1;
		}
		break;
	case ASM_TH:
		{
			VAR *v1;
			v1=stack.pop();
			switch(v1->type)
			{
			case VAR_INTEGER:
				v1->f=tanh(v1->val);
				v1->type=VAR_FLOATING;
				break;
			case VAR_FLOATING:
				v1->f=tanh(v1->f);
				break;
			};
			stack.c_push(v1);
//			v1->destroy();
//			delete v1;
		}
		break;
	case ASM_COTH:
		{
			VAR *v1;
			v1=stack.pop();
			switch(v1->type)
			{
			case VAR_INTEGER:
				v1->f=1.0f/tanh(v1->val);
				v1->type=VAR_FLOATING;
				break;
			case VAR_FLOATING:
				v1->f=1.0f/tanh(v1->f);
				break;
			};
			stack.c_push(v1);
//			v1->destroy();
//			delete v1;
		}
		break;
	case ASM_ACH:
		{
			VAR *v1;
			v1=stack.pop();
			switch(v1->type)
			{
			case VAR_INTEGER:
				v1->f=acosh(v1->val);
				v1->type=VAR_FLOATING;
				break;
			case VAR_FLOATING:
				v1->f=acosh(v1->f);
				break;
			};
			stack.c_push(v1);
//			v1->destroy();
//			delete v1;
		}
		break;
	case ASM_ASH:
		{
			VAR *v1;
			v1=stack.pop();
			switch(v1->type)
			{
			case VAR_INTEGER:
				v1->f=asinh(v1->val);
				v1->type=VAR_FLOATING;
				break;
			case VAR_FLOATING:
				v1->f=asinh(v1->f);
				break;
			};
			stack.c_push(v1);
//			v1->destroy();
//			delete v1;
		}
		break;
	case ASM_ATH:
		{
			VAR *v1;
			v1=stack.pop();
			switch(v1->type)
			{
			case VAR_INTEGER:
				v1->f=atanh(v1->val);
				v1->type=VAR_FLOATING;
				break;
			case VAR_FLOATING:
				v1->f=atanh(v1->f);
				break;
			};
			stack.c_push(v1);
//			v1->destroy();
//			delete v1;
		}
		break;
	case ASM_MOUSE_X:
		{
			VAR *v1=new VAR;
//			v1->init();
			v1->type=VAR_INTEGER;
			v1->val=mouse_x;
			stack.c_push(v1);
//			v1->destroy();
//			delete v1;
		}
		break;
	case ASM_MOUSE_Y:
		{
			VAR *v1=new VAR;
//			v1->init();
			v1->type=VAR_INTEGER;
			v1->val=mouse_y;
			stack.c_push(v1);
//			v1->destroy();
//			delete v1;
		}
		break;
	case ASM_MOUSE_Z:
		{
			VAR *v1=new VAR;
//			v1->init();
			v1->type=VAR_INTEGER;
			v1->val=mouse_z;
			stack.c_push(v1);
//			v1->destroy();
//			delete v1;
		}
		break;
	case ASM_MOUSE_B:
		{
			VAR *v1=new VAR;
//			v1->init();
			v1->type=VAR_INTEGER;
			v1->val=mouse_b;
			stack.c_push(v1);
//			v1->destroy();
//			delete v1;
		}
		break;
	case ASM_GET_KEY:
		{
			VAR *v1=new VAR;
//			v1->init();
			v1->type=VAR_INTEGER;
			if(keypressed())
				v1->val=readkey();
			else
				v1->val=0;
			stack.c_push(v1);
//			v1->destroy();
//			delete v1;
		}
		break;
	case ASM_INT:
		{
			VAR *v1;
			v1=stack.pop();
			switch(v1->type)
			{
			case VAR_BITMAP:
				v1->val=(v1->s!=NULL);
				v1->s=NULL;
				v1->type=VAR_INTEGER;
				break;
			case VAR_FLOATING:
				v1->val=(int)(v1->f);
				v1->type=VAR_INTEGER;
				break;
			};
			stack.c_push(v1);
//			v1->destroy();
//			delete v1;
		}
		break;
	case ASM_TIME:
		{
			VAR *v1=new VAR;
//			v1->init();
			v1->type=VAR_FLOATING;
			v1->f=(float)Atimer/SECS_TO_TIMER(1);
			stack.c_push(v1);
//			v1->destroy();
//			delete v1;
		}
		break;
	case ASM_LOAD:
		{
			VAR *v=stack.pop();
			if(v->type==VAR_STRING) {
				char *s=(char*)v->s;
				v->s=(byte*) load_bitmap(s,NULL);
				free(s);
				v->type=VAR_BITMAP;
				stack.c_push(v);
				}
			else
				delete v;
		}
		break;
	case ASM_DESTROY:
		{
			VAR *v=&var[get_short()];
			if(v->type==VAR_BITMAP && v->s!=NULL) {
				byte *pt=v->s;
				v->destroy();
				v->init();
				v->type=VAR_BITMAP;
				v->s=NULL;
				for(int i=0;i<nb_vars;i++)
					if(var[i].type==VAR_BITMAP && var[i].s==pt)
						var[i].s=NULL;
				}
			else {
				v->destroy();
				v->init();
				v->type=VAR_BITMAP;
				v->s=NULL;
				}
		}
		break;
	case ASM_SAVE:
		{
			VAR *v2=stack.pop();
			VAR *v1=stack.pop();
			if(v2->type==VAR_STRING && v1->type==VAR_BITMAP && v1->s!=NULL) {
				save_bitmap((char*)v2->s,(BITMAP*) v1->s,NULL);
				}
			if(v1->type==VAR_BITMAP) {
				v1->s=NULL;
				v1->type=VAR_NONE;
				}
			delete v1;
			delete v2;
		}
		break;
	case ASM_PUT:
		{
			VAR *v3=stack.pop();
			VAR *v2=stack.pop();
			VAR *v1=stack.pop();
			if(v2->type==VAR_FLOATING)	v2->val=(int)v2->f;
			if(v3->type==VAR_FLOATING)	v3->val=(int)v3->f;
			if(v1->type==VAR_BITMAP && v1->s!=NULL) {
				DRAW_OBJECT	draw_object;
				draw_object.type=DRAW_TYPE_BITMAP;
				draw_object.x[0]=v2->val;
				draw_object.y[0]=v3->val;
				draw_object.x[1]=v2->val+((BITMAP*)v1->s)->w;
				draw_object.y[1]=v3->val+((BITMAP*)v1->s)->h;
				if(g_useTextureCompression)
					allegro_gl_set_texture_format(GL_COMPRESSED_RGBA_ARB);
				else
					allegro_gl_set_texture_format(GL_RGBA8);
				allegro_gl_use_alpha_channel(true);
				draw_object.tex=allegro_gl_make_texture((BITMAP*)v1->s);
				allegro_gl_use_alpha_channel(false);
				glBindTexture(GL_TEXTURE_2D, draw_object.tex);
				glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
				glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR);
				draw_list.add(draw_object);
				}
			if(v1->type==VAR_BITMAP) {
				v1->s=NULL;
				v1->type=VAR_NONE;
				}
			delete v1;
			delete v2;
			delete v3;
		}
		break;
	case ASM_GET:
		{
			VAR *v5=stack.pop();
			VAR *v4=stack.pop();
			VAR *v3=stack.pop();
			VAR *v2=stack.pop();
			VAR *v1=&var[get_short()];
			if(v2->type==VAR_FLOATING)	v2->val=(int)v2->f;
			if(v3->type==VAR_FLOATING)	v3->val=(int)v3->f;
			if(v4->type==VAR_FLOATING)	v4->val=(int)v4->f;
			if(v5->type==VAR_FLOATING)	v5->val=(int)v5->f;
			if(v1->type==VAR_BITMAP && v1->s!=NULL) {
				byte *pt=v1->s;
				v1->destroy();
				v1->init();
				for(int i=0;i<nb_vars;i++)
					if(var[i].type==VAR_BITMAP && var[i].s==pt)
						var[i].s=NULL;
				}
			else {
				v1->destroy();
				v1->init();
				}
			v1->type=VAR_BITMAP;
			v1->s=(byte*) create_bitmap(v4->val,v5->val);		// Crée un bitmap de la taille donnée
			blit(screen,(BITMAP*) v1->s,v2->val,v3->val,0,0,v4->val,v5->val);
			delete v2;
			delete v3;
			delete v4;
			delete v5;
		}
		break;
	case ASM_CREATE:
		{
			VAR *v2=stack.pop();
			VAR *v1=stack.pop();
			VAR *v=&var[get_short()];
			if(v1->type==VAR_FLOATING)	v1->val=(int)v1->f;
			if(v2->type==VAR_FLOATING)	v2->val=(int)v2->f;
			if(v->type==VAR_BITMAP && v->s!=NULL) {
				byte *pt=v->s;
				v->destroy();
				v->init();
				v->type=VAR_BITMAP;
				v->s=NULL;
				for(int i=0;i<nb_vars;i++)
					if(var[i].type==VAR_BITMAP && var[i].s==pt)
						var[i].s=NULL;
				}
			else {
				v->destroy();
				v->init();
				v->type=VAR_BITMAP;
				}
			v->s=(byte*) create_bitmap(v1->val,v2->val);
			delete v1;
			delete v2;
		}
		break;
	case ASM_NB_PLAYER:
		{
			VAR *v=new VAR;
			v->type=VAR_INTEGER;
			v->val=NB_PLAYERS;
			stack.c_push(v);
		}
		break;
	case ASM_ANNIHILATED:
		{
			VAR *v=stack.pop();
			if(v->type==VAR_FLOATING)	v->val=(int)v->f;
			v->type=VAR_INTEGER;
			if(v->val>=0 && v->val<NB_PLAYERS)
				v->val=players.annihilated[v->val] ? 1 : 0;
			else
				v->val=1;
			stack.c_push(v);
		}
		break;
	case ASM_GET_UNIT_NUMBER:
		{
			VAR *v=new VAR;
			v->type=VAR_INTEGER;
			v->val=units.nb_unit;
			stack.c_push(v);
		}
		break;
	case ASM_GET_UNIT_OWNER:
		{
			VAR *v=stack.pop();
			if(v->type==VAR_FLOATING)	v->val=(int)v->f;
			if(v->val>=0 && v->val<=units.last_index) {
				if(units.unit[v->val].flags)
					v->val=units.unit[v->val].owner_id;
				else
					v->val=-1;
				}
			else
				v->val=-1;
			stack.c_push(v);
		}
		break;
	case ASM_GET_UNIT_NUMBER_FOR_PLAYER:
		{
			VAR *v=stack.pop();
			if(v->type==VAR_FLOATING)	v->val=(int)v->f;
			int player_id=v->val;
			v->val=0;
			if(player_id>=0 && player_id<NB_PLAYERS)
				for(int i=0;i<=units.last_index;i++)
					if(units.unit[i].flags!=0 && units.unit[i].owner_id==player_id)
						v->val++;
			stack.c_push(v);
		}
		break;
	case ASM_SET_CURRENT_PLAYER:
		{
			VAR *v=stack.pop();
			if(v) {
				if(v->type==VAR_FLOATING)	v->val=(int)v->f;
				current_player=v->val;
				delete v;
				}
		}
		break;
	case ASM_HAS_UNIT:
		{
			VAR *v=stack.pop();
			if(v) {
				if(v->type==VAR_FLOATING)	v->val=(int)v->f;
				int unit_type=v->val;
				if(v->type==VAR_STRING)
					unit_type=unit_manager.get_unit_index((char*)v->s);
				bool has=false;
				for(int i=0;i<=units.last_index;i++)
					if(units.unit[i].flags && units.unit[i].owner_id==current_player && units.unit[i].type_id==unit_type) {
						has=true;
						break;
						}
				v->destroy();
				v->type=VAR_INTEGER;
				v->val=has ? 1 : 0;
				}
			else {
				v=new VAR;
				v->init();
				v->type=VAR_INTEGER;
				v->val=0;
				}
			stack.c_push(v);
		}
		break;
	case ASM_CREATE_UNIT:
		{
			VAR *v=stack.pop();
			if(v) {
				if(v->type==VAR_FLOATING)	v->val=(int)v->f;
				if(v->type==VAR_STRING)
					v->val=unit_manager.get_unit_index((char*)v->s);
				v->type=VAR_INTEGER;
				v->val=units.create(v->val,current_player);
				}
			else {
				v=new VAR;
				v->init();
				v->type=VAR_INTEGER;
				v->val=-1;
				}
			stack.c_push(v);
		}
		break;
	case ASM_CHANGE_UNIT_OWNER:
		{
			VAR *owner=stack.pop();
			VAR *unit_id=stack.pop();
			if(owner!=NULL && unit_id!=NULL) {
				if(unit_id->type==VAR_FLOATING)	unit_id->val=(int)unit_id->f;
				if(unit_id->val>=0 && unit_id->val<=units.last_index && units.unit[unit_id->val].flags) {
					if(owner->type==VAR_FLOATING)	owner->val=(int)owner->f;
					units.unit[unit_id->val].owner_id=owner->val;
					}
				}
			if(owner)	delete owner;
			if(unit_id)	delete unit_id;
		}
		break;
	case ASM_MOVE_UNIT:
		{
			VAR *y=stack.pop();
			VAR *z=stack.pop();
			VAR *x=stack.pop();
			VAR *unit_id=stack.pop();
			if(unit_id==NULL) {
				unit_id=x;
				x=z;
				z=y;
				y=NULL;
				}
			if(x!=NULL && z!=NULL && unit_id!=NULL) {
				if(unit_id->type==VAR_FLOATING)	unit_id->val=(int)unit_id->f;
				if(unit_id->val>=0 && unit_id->val<=units.last_index && units.unit[unit_id->val].flags) {
					if(x->type==VAR_INTEGER)	x->f=x->val;
					if(z->type==VAR_INTEGER)	z->f=z->val;
					if(y!=NULL && y->type==VAR_INTEGER)	y->f=y->val;
					units.unit[unit_id->val].Pos.x=x->f;
					units.unit[unit_id->val].Pos.z=z->f;
					if(y)
						units.unit[unit_id->val].Pos.y=y->f;
					}
				}
			if(x)	delete x;
			if(y)	delete y;
			if(z)	delete z;
			if(unit_id)	delete unit_id;
		}
		break;
	case ASM_KILL_UNIT:
		{
			VAR *unit_id=stack.pop();
			if(unit_id!=NULL) {
				if(unit_id->type==VAR_FLOATING)	unit_id->val=(int)unit_id->f;
				if(unit_id->val>=0 && unit_id->val<=units.last_index && units.unit[unit_id->val].flags)
					units.unit[unit_id->val].hp=0.0f;
				}
			if(unit_id)	delete unit_id;
		}
		break;
	case ASM_KICK_UNIT:
		{
			VAR *damage=stack.pop();
			VAR *unit_id=stack.pop();
			if(unit_id!=NULL && damage!=NULL) {
				if(unit_id->type==VAR_FLOATING)	unit_id->val=(int)unit_id->f;
				if(unit_id->val>=0 && unit_id->val<=units.last_index && units.unit[unit_id->val].flags) {
					if(damage->type==VAR_INTEGER)	damage->f=damage->val;
					units.unit[unit_id->val].hp-=damage->f;
					}
				}
			if(unit_id)	delete unit_id;
			if(damage)	delete damage;
		}
		break;
	case ASM_PLAY:
		{
			VAR *v=stack.pop();
			if(v) {
				if(v->type==VAR_STRING) {
					VECTOR A;
					sound_manager.play((char*)v->s,A,false);
					}
				delete v;
				}
		}
		break;
	case ASM_MAP_W:
		{
			VAR *v=new VAR;
			v->init();
			v->type=VAR_INTEGER;
			v->val=map->map_w;
			stack.c_push(v);
		}
		break;
	case ASM_MAP_H:
		{
			VAR *v=new VAR;
			v->init();
			v->type=VAR_INTEGER;
			v->val=map->map_h;
			stack.c_push(v);
		}
		break;
	case ASM_PLAYER_SIDE:
		{
			VAR *v=stack.pop();
			if(v) {
				if(v->type==VAR_FLOATING)	v->val=(int)v->f;
				v->type=VAR_STRING;
				if(v->val>=0 && v->val<NB_PLAYERS)
					v->s=(byte*)strdup(players.side[v->val]);
				else
					v->s=(byte*)strdup("none");
				v->val=strlen((char*)v->s);
				}
			else {
				Console->AddEntry("stack empty");
				v=new VAR;
				v->init();
				v->type=VAR_STRING;
				v->s=(byte*)strdup("none");
				v->val=4;
				}
			stack.c_push(v);
		}
		break;
	};
	}

	amx=mouse_x;
	amy=mouse_y;
	amz=mouse_z;
	amb=mouse_b;
	return 0;
}
