/*  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.                                                       |
\----------------------------------------------------------------------*/

#ifdef CWDEBUG
#include <libcwd/sys.h>
#include <libcwd/debug.h>
#endif
#include "stdafx.h"
#include "matrix.h"
#include "TA3D_NameSpace.h"
#include "ta3dbase.h"
#include "EngineClass.h"
#include "UnitEngine.h"
#include "script.h"

LUA_PROGRAM	*lua_program = NULL;
MAP *lua_map = NULL;

int function_print( lua_State *L )		// ta3d_print( x, y, str )
{
	const char *str = lua_tostring( L, -1 );		// Read the result
	if( str ) {
		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] = (float) lua_tonumber( L, -3 );
		draw_obj.y[0] = (float) lua_tonumber( L, -2 );
		draw_obj.text = strdup( TRANSLATE( str ).c_str() );
		lua_program->draw_list.add( draw_obj );
		}
	lua_pop( L, 3 );
	return 0;
}

int function_logmsg( lua_State *L )		// ta3d_logmsg( str )
{
	const char *str = lua_tostring( L, -1 );		// Read the result
	if( str )
		Console->AddEntry( str );
	lua_pop( L, 1 );
	return 0;
}

int function_line( lua_State *L )		// ta3d_line( x1,y1,x2,y2,r,g,b )
{
	DRAW_OBJECT draw_obj;
	draw_obj.type = DRAW_TYPE_LINE;
	draw_obj.r[0] = (float) lua_tonumber( L, -3 );
	draw_obj.g[0] = (float) lua_tonumber( L, -2 );
	draw_obj.b[0] = (float) lua_tonumber( L, -1 );
	draw_obj.x[0] = (float) lua_tonumber( L, -7 );
	draw_obj.y[0] = (float) lua_tonumber( L, -6 );
	draw_obj.x[1] = (float) lua_tonumber( L, -5 );
	draw_obj.y[1] = (float) lua_tonumber( L, -4 );
	lua_program->draw_list.add( draw_obj );
	lua_pop( L, 7 );

	return 0;
}

int function_point( lua_State *L )		// ta3d_line( x,y,r,g,b )
{
	DRAW_OBJECT draw_obj;
	draw_obj.type = DRAW_TYPE_POINT;
	draw_obj.r[0] = (float) lua_tonumber( L, -3 );
	draw_obj.g[0] = (float) lua_tonumber( L, -2 );
	draw_obj.b[0] = (float) lua_tonumber( L, -1 );
	draw_obj.x[0] = (float) lua_tonumber( L, -5 );
	draw_obj.y[0] = (float) lua_tonumber( L, -4 );
	lua_program->draw_list.add( draw_obj );
	lua_pop( L, 5 );

	return 0;
}

int function_triangle( lua_State *L )		// ta3d_line( x1,y1,x2,y2,x3,y3,r,g,b )
{
	DRAW_OBJECT draw_obj;
	draw_obj.type = DRAW_TYPE_TRIANGLE;
	draw_obj.r[0] = (float) lua_tonumber( L, -3 );
	draw_obj.g[0] = (float) lua_tonumber( L, -2 );
	draw_obj.b[0] = (float) lua_tonumber( L, -1 );
	draw_obj.x[0] = (float) lua_tonumber( L, -9 );
	draw_obj.y[0] = (float) lua_tonumber( L, -8 );
	draw_obj.x[1] = (float) lua_tonumber( L, -7 );
	draw_obj.y[1] = (float) lua_tonumber( L, -6 );
	draw_obj.x[2] = (float) lua_tonumber( L, -5 );
	draw_obj.y[2] = (float) lua_tonumber( L, -4 );
	lua_program->draw_list.add( draw_obj );
	lua_pop( L, 9 );

	return 0;
}

int function_cls( lua_State *L )		// ta3d_cls()
{
	lua_program->draw_list.destroy();
	return 0;
}

int lua_signal = 0;

int function_signal( lua_State *L )		// ta3d_signal( signal )
{
	lua_signal = (int) lua_tonumber( L, -1 );
	lua_pop( L, 1 );
	return 0;
}

int function_box( lua_State *L )		// ta3d_box( x1,y1,x2,y2,r,g,b )
{
	DRAW_OBJECT draw_obj;
	draw_obj.type = DRAW_TYPE_BOX;
	draw_obj.r[0] = (float) lua_tonumber( L, -3 );
	draw_obj.g[0] = (float) lua_tonumber( L, -2 );
	draw_obj.b[0] = (float) lua_tonumber( L, -1 );
	draw_obj.x[0] = (float) lua_tonumber( L, -7 );
	draw_obj.y[0] = (float) lua_tonumber( L, -6 );
	draw_obj.x[1] = (float) lua_tonumber( L, -5 );
	draw_obj.y[1] = (float) lua_tonumber( L, -4 );
	lua_program->draw_list.add( draw_obj );
	lua_pop( L, 7 );

	return 0;
}

int function_fillbox( lua_State *L )		// ta3d_fillbox( x1,y1,x2,y2,r,g,b )
{
	DRAW_OBJECT draw_obj;
	draw_obj.type = DRAW_TYPE_FILLBOX;
	draw_obj.r[0] = (float) lua_tonumber( L, -3 );
	draw_obj.g[0] = (float) lua_tonumber( L, -2 );
	draw_obj.b[0] = (float) lua_tonumber( L, -1 );
	draw_obj.x[0] = (float) lua_tonumber( L, -7 );
	draw_obj.y[0] = (float) lua_tonumber( L, -6 );
	draw_obj.x[1] = (float) lua_tonumber( L, -5 );
	draw_obj.y[1] = (float) lua_tonumber( L, -4 );
	lua_program->draw_list.add( draw_obj );
	lua_pop( L, 7 );

	return 0;
}

int function_circle( lua_State *L )		// ta3d_circle( x,y,ray,r,g,b )
{
	DRAW_OBJECT draw_obj;
	draw_obj.type = DRAW_TYPE_CIRCLE;
	draw_obj.r[0] = (float) lua_tonumber( L, -3 );
	draw_obj.g[0] = (float) lua_tonumber( L, -2 );
	draw_obj.b[0] = (float) lua_tonumber( L, -1 );
	draw_obj.x[0] = (float) lua_tonumber( L, -6 );
	draw_obj.y[0] = (float) lua_tonumber( L, -5 );
	draw_obj.r[1] = (float) lua_tonumber( L, -4 );
	lua_program->draw_list.add( draw_obj );
	lua_pop( L, 6 );

	return 0;
}

int function_mouse_x( lua_State *L )		// ta3d_mouse_x()
{
	lua_pushnumber( L, mouse_x );
	return 1;
}

int function_mouse_y( lua_State *L )		// ta3d_mouse_y()
{
	lua_pushnumber( L, mouse_y );
	return 1;
}

int function_mouse_z( lua_State *L )		// ta3d_mouse_z()
{
	lua_pushnumber( L, mouse_z );
	return 1;
}

int function_mouse_b( lua_State *L )		// ta3d_mouse_b()
{
	lua_pushnumber( L, mouse_b );
	return 1;
}

int function_get_key( lua_State *L )		// ta3d_get_key()
{
	if(keypressed())
		lua_pushnumber( L, readkey() );
	else
		lua_pushnumber( L, 0 );
	return 1;
}

int function_time( lua_State *L )		// ta3d_time()
{
	lua_pushnumber( L, msec_timer * 0.001f );
	return 1;
}

int function_draw_image( lua_State *L )		// ta3d_draw_image( str image_name, x1, y1, x2, y2 )
{
	DRAW_OBJECT draw_obj;
	draw_obj.type = DRAW_TYPE_BITMAP;
	draw_obj.x[0] = (float) lua_tonumber( L, -4 );
	draw_obj.y[0] = (float) lua_tonumber( L, -3 );
	draw_obj.x[1] = (float) lua_tonumber( L, -2 );
	draw_obj.y[1] = (float) lua_tonumber( L, -1 );
	draw_obj.tex = gfx->load_texture( TRANSLATE( lua_tostring( L, -5 ) ) );
	lua_program->draw_list.add( draw_obj );
	lua_pop( L, 5 );

	return 0;
}

int function_nb_players( lua_State *L )		// ta3d_nb_players()
{
	lua_pushnumber( L, NB_PLAYERS );
	return 1;
}

int function_get_unit_number_for_player( lua_State *L )		// ta3d_get_unit_number_for_player( player_id )
{
	int player_id = (int) lua_tonumber( L, -1 );
	lua_pop( L, 1 );
	if( player_id >= 0 && player_id < NB_PLAYERS ) {
		int n = 0;
		for( uint16 e = 0 ; e < units.index_list_size ; e++ ) {
			uint16 i = units.idx_list[ e ];
			if( units.unit[i].flags != 0 && units.unit[ i ].owner_id == player_id )
				n++;
			}
		lua_pushnumber( L, n );
		}
	else
		lua_pushnumber( L, 0 );
	return 1;
}

int function_get_unit_owner( lua_State *L )		// ta3d_get_unit_owner( unit_id )
{
	int unit_idx = (int) lua_tonumber( L, -1 );
	lua_pop( L, 1 );
	if( unit_idx >= 0 && unit_idx < units.max_unit ) {
		if( units.unit[ unit_idx ].flags )
			lua_pushnumber( L, units.unit[ unit_idx ].owner_id );
		else
			lua_pushnumber( L, -1 );
		}
	else
		lua_pushnumber( L, -1 );
	return 1;
}

int function_get_unit_number( lua_State *L )		// ta3d_get_unit_number()
{
	lua_pushnumber( L, units.nb_unit );
	return 1;
}

int function_get_max_unit_number( lua_State *L )		// ta3d_get_max_unit_number()
{
	lua_pushnumber( L, units.max_unit );
	return 1;
}

int function_annihilated( lua_State *L )		// ta3d_annihilated( player_id )
{
	int player_id = (int) lua_tonumber( L, -1 );
	lua_pop( L, 1 );
	if( player_id >= 0 && player_id < NB_PLAYERS )
		lua_pushboolean( L, players.annihilated[ player_id ] );
	else
		lua_pushboolean( L, false );
	return 1;
}

int function_has_unit( lua_State *L )		// ta3d_has_unit( player_id, unit_type_id )
{
	int player_id = (int) lua_tonumber( L, -2 );
	if( player_id >= 0 && player_id < NB_PLAYERS ) {
		int unit_type = lua_isstring( L, -1 ) ? unit_manager.get_unit_index( lua_tostring( L, -1 ) ) : (int) lua_tonumber( L, -1 ) ;
		bool has = false;
		uint16 last_possible_idx = min( (int)units.max_unit, ( player_id + 1 ) * MAX_UNIT_PER_PLAYER);
		for( uint16 i = player_id * MAX_UNIT_PER_PLAYER ; i < last_possible_idx ; i++ )
			if( units.unit[i].flags && units.unit[i].owner_id == player_id && units.unit[i].type_id == unit_type ) {
				has=true;
				break;
				}
		lua_pop( L, 2 );
		lua_pushboolean( L, has );
		}
	else {
		lua_pop( L, 2 );
		lua_pushboolean( L, false );
		}
	return 1;
}

int function_move_unit( lua_State *L )		// ta3d_move_unit( unit_id, x, z )
{
	int unit_id = (int) lua_tonumber( L, -3 );

	if( unit_id >= 0 && unit_id < units.max_unit && units.unit[ unit_id ].flags ) {
		units.EnterCS_from_outside();

		units.unit[ unit_id ].Pos.x = (float) lua_tonumber( L, -2 );
		units.unit[ unit_id ].Pos.z = (float) lua_tonumber( L, -1 );

		units.unit[ unit_id ].clear_from_map();

		int PX = ((int)(units.unit[ unit_id ].Pos.x + lua_map->map_w_d)>>3);
		int PY = ((int)(units.unit[ unit_id ].Pos.z + lua_map->map_h_d)>>3);
		if( !can_be_there( PX, PY, lua_map, units.unit[ unit_id ].type_id, units.unit[ unit_id ].owner_id ) ) {
			bool found = false;
			for( int r = 1 ; r < 120 && !found ; r++ ) {		// Circular check
				int r2 = r * r;
				for( int y = 0 ; y <= r ; y++ ) {
					int x = (int)(sqrt( r2 - y * y ) + 0.5f);
					if( can_be_there( PX+x, PY+y, lua_map, units.unit[ unit_id ].type_id, units.unit[ unit_id ].owner_id ) ) {
						PX += x;
						PY += y;
						found = true;
						break;
						}
					if( can_be_there( PX-x, PY+y, lua_map, units.unit[ unit_id ].type_id, units.unit[ unit_id ].owner_id ) ) {
						PX -= x;
						PY += y;
						found = true;
						break;
						}
					if( can_be_there( PX+x, PY-y, lua_map, units.unit[ unit_id ].type_id, units.unit[ unit_id ].owner_id ) ) {
						PX += x;
						PY -= y;
						found = true;
						break;
						}
					if( can_be_there( PX-x, PY-y, lua_map, units.unit[ unit_id ].type_id, units.unit[ unit_id ].owner_id ) ) {
						PX -= x;
						PY -= y;
						found = true;
						break;
						}
					}
				}
			if( found ) {
				units.unit[ unit_id ].Pos.x = (PX<<3) + 8 - lua_map->map_w_d;
				units.unit[ unit_id ].Pos.z = (PY<<3) + 8 - lua_map->map_h_d;
				if( units.unit[ unit_id ].mission && (units.unit[ unit_id ].mission->flags & MISSION_FLAG_MOVE) )
					units.unit[ unit_id ].mission->flags |= MISSION_FLAG_REFRESH_PATH;
				}
			else {
				int prev = 0;
				for( int i = 0 ; i < units.nb_unit ; i++ )
					if( units.idx_list[ i ] == unit_id ) {
						prev = i;
						break;
						}
				units.kill( unit_id, lua_map, prev);
				unit_id = -1;
				}
			}
		if( unit_id >= 0 ) {
			units.unit[ unit_id ].cur_px = PX;
			units.unit[ unit_id ].cur_py = PY;

			VECTOR target_pos = units.unit[ unit_id ].Pos;
			target_pos.x=((int)(target_pos.x) + lua_map->map_w_d)>>3;
			target_pos.z=((int)(target_pos.z) + lua_map->map_h_d)>>3;
			target_pos.y = max( lua_map->get_max_rect_h((int)target_pos.x,(int)target_pos.z, unit_manager.unit_type[ units.unit[ unit_id ].type_id ].FootprintX, unit_manager.unit_type[ units.unit[ unit_id ].type_id ].FootprintZ ), lua_map->sealvl);
			units.unit[ unit_id ].Pos.y = target_pos.y;
			units.unit[ unit_id ].draw_on_map();
			}

		units.LeaveCS_from_outside();
		}
	lua_pop( L, 3 );

	return 0;
}

int function_create_unit( lua_State *L )		// ta3d_create_unit( player_id, unit_type_id, x, z )
{
	int player_id = (int) lua_tonumber( L, -4 );
	int unit_type_id = lua_isstring( L, -3 ) ? unit_manager.get_unit_index( lua_tostring( L, -3 ) ) : (int) lua_tonumber( L, -3 ) ;
	float x = (float) lua_tonumber( L, -2 );
	float z = (float) lua_tonumber( L, -1 );

	lua_pop( L, 4 );

	if( unit_type_id >= 0 && unit_type_id < unit_manager.nb_unit && player_id >= 0 && player_id < NB_PLAYERS ) {
		units.EnterCS_from_outside();
		int idx = units.create( unit_type_id, player_id );
		if( idx >= 0 && idx < units.max_unit && units.unit[ idx ].flags )
			units.unit[ idx ].draw_on_map();
		units.LeaveCS_from_outside();

		if( idx >= 0 && idx < units.max_unit && units.unit[ idx ].flags ) {
			lua_pushnumber( L, idx );
			lua_pushnumber( L, x );
			lua_pushnumber( L, z );
			function_move_unit( L );		// Move it to the correct location
			}

		if( idx >= 0 && idx < units.max_unit && units.unit[ idx ].flags )
			lua_pushnumber( L, idx );
		else
			lua_pushnumber( L, -1 );
		}
	else
		lua_pushnumber( L, -1 );

	return 1;
}

int function_change_unit_owner( lua_State *L )		// ta3d_change_unit_owner( unit_id, player_id )
{
	int player_id = (int) lua_tonumber( L, -1 );
	int unit_id = (int) lua_tonumber( L, -2 );
	lua_pop( L, 2 );

	if( unit_id >= 0 && unit_id < units.max_unit && player_id >= 0 && player_id < NB_PLAYERS && units.unit[ unit_id ].flags ) {
		units.EnterCS_from_outside();
		units.unit[ unit_id ].owner_id = player_id;
		units.LeaveCS_from_outside();
		}

	return 0;
}

int function_local_player( lua_State *L )		// ta3d_local_player()
{
	lua_pushnumber( L, players.local_human_id );
	return 1;
}

int function_map_w( lua_State *L )		// ta3d_map_w()
{
	lua_pushnumber( L, lua_map->map_w );
	return 1;
}

int function_map_h( lua_State *L )		// ta3d_map_h()
{
	lua_pushnumber( L, lua_map->map_h );
	return 1;
}

int function_player_side( lua_State *L )		// ta3d_player_side( player_id )
{
	int player_id = (int) lua_tonumber( L, -1 );
	lua_pop( L, 1 );

	if( player_id >= 0 && player_id < NB_PLAYERS )
		lua_pushstring( L, players.side[ player_id ] );
	else
		lua_pushstring( L, "" );

	return 1;
}

int function_unit_x( lua_State *L )		// ta3d_unit_x( unit_id )
{
	int unit_id = (int) lua_tonumber( L, -1 );
	lua_pop( L, 1 );

	if( unit_id >= 0 && unit_id < units.max_unit && units.unit[ unit_id ].flags ) {
		units.EnterCS_from_outside();
		lua_pushnumber( L, units.unit[ unit_id ].Pos.x );
		units.LeaveCS_from_outside();
		}
	else
		lua_pushnumber( L, 0 );

	return 1;
}

int function_unit_y( lua_State *L )		// ta3d_unit_y( unit_id )
{
	int unit_id = (int) lua_tonumber( L, -1 );
	lua_pop( L, 1 );

	if( unit_id >= 0 && unit_id < units.max_unit && units.unit[ unit_id ].flags ) {
		units.EnterCS_from_outside();
		lua_pushnumber( L, units.unit[ unit_id ].Pos.y );
		units.LeaveCS_from_outside();
		}
	else
		lua_pushnumber( L, 0 );

	return 1;
}

int function_unit_z( lua_State *L )		// ta3d_unit_z( unit_id )
{
	int unit_id = (int) lua_tonumber( L, -1 );
	lua_pop( L, 1 );

	if( unit_id >= 0 && unit_id < units.max_unit && units.unit[ unit_id ].flags ) {
		units.EnterCS_from_outside();
		lua_pushnumber( L, units.unit[ unit_id ].Pos.z );
		units.LeaveCS_from_outside();
		}
	else
		lua_pushnumber( L, 0 );

	return 1;
}

int function_kill_unit( lua_State *L )		// ta3d_kill_unit( unit_id )
{
	int unit_id = (int) lua_tonumber( L, -1 );
	lua_pop( L, 1 );

	if( unit_id >= 0 && unit_id < units.max_unit && units.unit[ unit_id ].flags ) {
		units.EnterCS_from_outside();

		units.unit[ unit_id ].hp = 0.0f;

		units.LeaveCS_from_outside();
		}

	return 0;
}

int function_kick_unit( lua_State *L )		// ta3d_kick_unit( unit_id, damage )
{
	int unit_id = (int) lua_tonumber( L, -2 );
	float damage = (float) lua_tonumber( L, -1 );
	lua_pop( L, 2 );

	if( unit_id >= 0 && unit_id < units.max_unit && units.unit[ unit_id ].flags ) {
		units.EnterCS_from_outside();

		units.unit[ unit_id ].hp -= damage;

		units.LeaveCS_from_outside();
		}

	return 0;
}

int function_play( lua_State *L )		// ta3d_play( filename )
{
	sound_manager->PlaySound( (char*) lua_tostring( L, -1 ), false );
	lua_pop( L, 1 );

	return 0;
}

int function_set_cam_pos( lua_State *L )		// ta3d_set_cam_pos( player_id,x,z )
{
	if( (int) lua_tonumber( L, -3 ) == players.local_human_id ) {
		game_cam->RPos.x = (float) lua_tonumber( L, -2 );
		game_cam->RPos.z = (float) lua_tonumber( L, -1 );
		}
	lua_pop( L, 3 );

	return 0;
}

int function_set_cam_mode( lua_State *L )		// ta3d_set_cam_mode( mode )	-> uses the signal system
{
	if( lua_toboolean( L, -1 ) )
		lua_signal = 5;
	else
		lua_signal = 4;
	lua_pop( L, 1 );

	return 0;
}

int function_clf( lua_State *L )				// ta3d_clf()
{
	lua_map->clear_FOW();
	for( int i = 0 ; i < units.index_list_size ; i++ )
		units.unit[ units.idx_list[ i ] ].old_px = -10000;
	return 0;
}

int function_start_x( lua_State *L )			// ta3d_start_x( player_id )
{
	int player_id = (int) lua_tonumber( L, -1 );
	lua_pop( L, 1 );

	if( player_id >= 0 && player_id < players.nb_player )
		lua_pushnumber( L, (lua_map->ota_data.startX[ player_id ] - lua_map->map_w) * 0.5f );
	else
		lua_pushnumber( L, 0 );
	return 1;
}

int function_start_z( lua_State *L )			// ta3d_start_z( player_id )
{
	int player_id = (int) lua_tonumber( L, -1 );
	lua_pop( L, 1 );

	if( player_id >= 0 && player_id < players.nb_player )
		lua_pushnumber( L, (lua_map->ota_data.startZ[ player_id ] - lua_map->map_h) * 0.5f );
	else
		lua_pushnumber( L, 0 );
	return 1;
}

int function_init_res( lua_State *L )			// ta3d_init_res()
{
	for( uint16 i = 0 ; i < players.nb_player ; i++ ) {
		players.metal[i] = players.com_metal[i];
		players.energy[i] = players.com_energy[i];
		}
	return 0;
}

int function_give_metal( lua_State *L )			// ta3d_give_metal( player_id, amount )
{
	int player_id = (int) lua_tonumber( L, -2 );
	float amount = (float) lua_tonumber( L, -1 );
	lua_pop( L, 2 );

	if( player_id >= 0 && player_id < players.nb_player ) {
		units.EnterCS_from_outside();
		players.metal[ player_id ] += amount;
		players.c_metal[ player_id ] = players.metal[ player_id ];
		units.LeaveCS_from_outside();
		}
	return 0;
}

int function_give_energy( lua_State *L )			// ta3d_give_energy( player_id, amount )
{
	int player_id = (int) lua_tonumber( L, -2 );
	float amount = (float) lua_tonumber( L, -1 );
	lua_pop( L, 2 );

	if( player_id >= 0 && player_id < players.nb_player ) {
		units.EnterCS_from_outside();
		players.energy[ player_id ] += amount;
		players.c_energy[ player_id ] = players.energy[ player_id ];
		units.LeaveCS_from_outside();
		}
	return 0;
}

int function_commander( lua_State *L )				// ta3d_commander( player_id )
{
	int player_id = (int) lua_tonumber( L, -1 );
	lua_pop( L, 1 );

	if( player_id >= 0 && player_id < NB_PLAYERS )		// make sure we have a player
		for( int i = 0 ; i < ta3d_sidedata.nb_side ; i++ )
			if( strcasecmp(ta3d_sidedata.side_name[ i ], players.side[ player_id ]) == 0  ) {
				lua_pushstring( L, ta3d_sidedata.side_com[ i ] );
				break;
				}
	else
		lua_pushstring( L, "" );
	return 1;
}

int function_attack( lua_State *L )					// ta3d_attack( attacker_id, target_id )
{
	int attacker_idx = (int) lua_tonumber( L, -2 );
	int target_idx = (int) lua_tonumber( L, -1 );
	lua_pop( L, 2 );

	if( attacker_idx >= 0 && attacker_idx < units.max_unit && units.unit[ attacker_idx ].flags )		// make sure we have an attacker and a target
		if( target_idx >= 0 && target_idx < units.max_unit && units.unit[ target_idx ].flags ) {
			units.EnterCS_from_outside();
			units.unit[ attacker_idx ].set_mission( MISSION_ATTACK,&(units.unit[ target_idx ].Pos),false,0,true,&(units.unit[ target_idx ]) );
			units.LeaveCS_from_outside();
			}
	return 0;
}

int function_wait( lua_State *L )			// ta3d_wait()
{
	lua_program->waiting = true;
	return 0;
}

int function_sleep( lua_State *L )			// ta3d_sleep( time )
{
	lua_program->sleeping = true;
	lua_program->sleep_time = (float) lua_tonumber( L, -1 );
	lua_pop( L, 1 );
	return 0;
}

void register_functions( lua_State *L )
{
	lua_register( L, "ta3d_print", function_print );
	lua_register( L, "ta3d_logmsg", function_logmsg );
	lua_register( L, "ta3d_line", function_line );
	lua_register( L, "ta3d_cls", function_cls );
	lua_register( L, "ta3d_point", function_point );
	lua_register( L, "ta3d_triangle", function_triangle );
	lua_register( L, "ta3d_signal", function_signal );
	lua_register( L, "ta3d_box", function_box );
	lua_register( L, "ta3d_fillbox", function_fillbox );
	lua_register( L, "ta3d_circle", function_circle );
	lua_register( L, "ta3d_mouse_x", function_mouse_x );
	lua_register( L, "ta3d_mouse_y", function_mouse_y );
	lua_register( L, "ta3d_mouse_z", function_mouse_z );
	lua_register( L, "ta3d_mouse_b", function_mouse_b );
	lua_register( L, "ta3d_get_key", function_get_key );
	lua_register( L, "ta3d_time", function_time );
	lua_register( L, "ta3d_draw_image", function_draw_image );
	lua_register( L, "ta3d_nb_players", function_nb_players );
	lua_register( L, "ta3d_get_unit_number_for_player", function_get_unit_number_for_player );
	lua_register( L, "ta3d_get_unit_owner", function_get_unit_owner );
	lua_register( L, "ta3d_get_unit_number", function_get_unit_number );
	lua_register( L, "ta3d_get_max_unit_number", function_get_max_unit_number );
	lua_register( L, "ta3d_annihilated", function_annihilated );
	lua_register( L, "ta3d_has_unit", function_has_unit );
	lua_register( L, "ta3d_create_unit", function_create_unit );
	lua_register( L, "ta3d_change_unit_owner", function_change_unit_owner );
	lua_register( L, "ta3d_local_player", function_local_player );
	lua_register( L, "ta3d_map_w", function_map_w );
	lua_register( L, "ta3d_map_h", function_map_h );
	lua_register( L, "ta3d_player_side", function_player_side );
	lua_register( L, "ta3d_unit_x", function_unit_x );
	lua_register( L, "ta3d_unit_y", function_unit_y );
	lua_register( L, "ta3d_unit_z", function_unit_z );
	lua_register( L, "ta3d_move_unit", function_move_unit );
	lua_register( L, "ta3d_kill_unit", function_kill_unit );
	lua_register( L, "ta3d_kick_unit", function_kick_unit );
	lua_register( L, "ta3d_play", function_play );
	lua_register( L, "ta3d_set_cam_pos", function_set_cam_pos );
	lua_register( L, "ta3d_set_cam_mode", function_set_cam_mode );
	lua_register( L, "ta3d_clf", function_clf );
	lua_register( L, "ta3d_start_x", function_start_x );
	lua_register( L, "ta3d_start_z", function_start_z );
	lua_register( L, "ta3d_init_res", function_init_res );
	lua_register( L, "ta3d_give_metal", function_give_metal );
	lua_register( L, "ta3d_give_energy", function_give_energy );
	lua_register( L, "ta3d_commander", function_commander );
	lua_register( L, "ta3d_attack", function_attack );
	lua_register( L, "ta3d_wait", function_wait );
	lua_register( L, "ta3d_sleep", function_sleep );
}

void LUA_PROGRAM::load(char *filename, MAP *map)					// Load a lua script
{
	destroy();			// Au cas où

	uint32 filesize = 0;
	buffer = HPIManager->PullFromHPI( filename , &filesize );
	if( buffer ) {
		int n = 0;
		char *f = NULL;
		while( ( f = strstr( (char*)buffer, "#include" ) ) != NULL && n < 20 ) {
			char name[101];
			name[0] = 0;
			strcat( name, "scripts/" );
			int i;
			for( i = 0 ; i < 100 & f[ i + 10 ] != '"' ; i++ )
				name[ i + 8 ] = f[ i + 10 ];
			name[ i + 8 ] = 0;
			uint32 filesize2 = 0;
			byte *buffer2 = HPIManager->PullFromHPI( name, &filesize2 );
			if( buffer2 ) {
				byte *buffer3 = (byte*) malloc( filesize + filesize2 );
				memset( buffer3, 0, filesize + filesize2 );
				memcpy( buffer3, buffer, f - (char*)buffer );
				memcpy( buffer3 + (f - (char*)buffer), buffer2, filesize2 );
				memcpy( buffer3 + (f - (char*)buffer) + filesize2, f + i + 11, filesize - ( f + i + 11 - (char*)buffer ) );
				filesize += filesize2 - i - 11;
				free( buffer );
				free( buffer2 );
				buffer = buffer3;
				}
			else
				break;
			n++;
			}

		L = lua_open();				// Create a lua state object

		if( L == NULL ) {
			running = false;
			free( buffer );
			buffer = NULL;
			return;
			}

		lua_program = this;
		lua_map = map;

		lua_gc( L, LUA_GCSTOP, 0 );		// Load libraries
		luaL_openlibs( L );
		lua_gc( L, LUA_GCRESTART, 0 );

		register_functions( L );

		if( luaL_dobuffer( L, buffer, filesize ) ) {	// Load the lua chunk
			if( lua_tostring( L, -1 ) != "" ) {
				Console->AddEntry( "LUA ERROR: %s", lua_tostring( L, -1 ) );
				printf("LUA ERROR: %s\n", lua_tostring( L, -1 ) );
				}

			running = false;
			lua_close( L );
			free( buffer );
			L = NULL;
			buffer = NULL;
			}
		else
			running = true;
		}
	else
		running = false;
}

int LUA_PROGRAM::run(MAP *map,float dt,int viewer_id)									// Execute le script
{
	draw_list.draw(gfx->TA_font);			// Execute la liste de commandes de dessin

	if( !running )	return	-1;

	lua_program = this;
	lua_map = map;

	asm_timer += dt;

	if(sleeping) {
		sleep_time-=dt;
		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
		}

	lua_signal = 0;

	lua_pushstring( L, "main" );
	lua_gettable( L, LUA_GLOBALSINDEX );
	try {
		if( lua_pcall( L, 0, 1, 0 ) ) {
			if( lua_tostring( L, -1 ) != "" ) {
				Console->AddEntry( "LUA ERROR: %s", lua_tostring( L, -1 ) );
				printf("LUA ERROR: %s\n", lua_tostring( L, -1 ) );
				}
			running = false;
			return -1;
			}
		}
	catch(...)
	{
		if( lua_tostring( L, -1 ) != "" ) {
			Console->AddEntry( "LUA ERROR: %s", lua_tostring( L, -1 ) );
			printf("LUA ERROR: %s\n", lua_tostring( L, -1 ) );
			}
		running = false;
		return -1;
	};

	int result = (int) lua_tonumber( L, lua_gettop( L ) );		// Read the result
	lua_pop( L, 1 );

	amx=mouse_x;
	amy=mouse_y;
	amz=mouse_z;
	amb=mouse_b;

	if( lua_signal )
		result = lua_signal;

	return result;
}

void DRAW_LIST::draw(GFX_FONT &fnt)
{
	glPushMatrix();
	glScalef(SCREEN_W/640.0f,SCREEN_H/480.0f,1.0f);
	switch(prim.type)
	{
	case DRAW_TYPE_POINT:
		glBegin(GL_POINTS);
			glColor3f(prim.r[0],prim.g[0],prim.b[0]);
			glVertex2f(prim.x[0],prim.y[0]);
		glEnd();
		break;
	case DRAW_TYPE_LINE:
		glBegin(GL_LINES);
			glColor3f(prim.r[0],prim.g[0],prim.b[0]);
			glVertex2f(prim.x[0],prim.y[0]);
			glVertex2f(prim.x[1],prim.y[1]);
		glEnd();
		break;
	case DRAW_TYPE_CIRCLE:
		glBegin(GL_LINE_STRIP);
			glColor3f(prim.r[0],prim.g[0],prim.b[0]);
			{
				int max = (int)(sqrt(prim.r[1])*2.0f)*2;
				if(max>0)
					for(int i=0;i<=prim.r[1]*10;i++)
						glVertex2f(prim.x[0]+prim.r[1]*cos(i*6.2831853072f/max),prim.y[0]+prim.r[1]*sin(i*6.2831853072f/max));
			}
		glEnd();
		break;
	case DRAW_TYPE_TRIANGLE:
		glBegin(GL_TRIANGLES);
			glColor3f(prim.r[0],prim.g[0],prim.b[0]);
			glVertex2f(prim.x[0],prim.y[0]);
			glVertex2f(prim.x[1],prim.y[1]);
			glVertex2f(prim.x[2],prim.y[2]);
		glEnd();
		break;
	case DRAW_TYPE_BOX:
		glBegin(GL_LINE_STRIP);
			glColor3f(prim.r[0],prim.g[0],prim.b[0]);
			glVertex2f(prim.x[0],prim.y[0]);
			glVertex2f(prim.x[1],prim.y[0]);
			glVertex2f(prim.x[1],prim.y[1]);
			glVertex2f(prim.x[0],prim.y[1]);
			glVertex2f(prim.x[0],prim.y[0]);
		glEnd();
		break;
	case DRAW_TYPE_FILLBOX:
		glBegin(GL_QUADS);
			glColor3f(prim.r[0],prim.g[0],prim.b[0]);
			glVertex2f(prim.x[0],prim.y[0]);
			glVertex2f(prim.x[1],prim.y[0]);
			glVertex2f(prim.x[1],prim.y[1]);
			glVertex2f(prim.x[0],prim.y[1]);
		glEnd();
		break;
	case DRAW_TYPE_TEXT:
		glEnable(GL_BLEND);
		glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
		gfx->print(fnt,prim.x[0],prim.y[0],0.0f,makeacol32((int)(prim.r[0]*255.0f),(int)(prim.g[0]*255.0f),(int)(prim.b[0]*255.0f), 0xFF),prim.text);
		glDisable(GL_BLEND);
		break;
	case DRAW_TYPE_BITMAP:
		glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
		glEnable(GL_BLEND);
		gfx->drawtexture(prim.tex,prim.x[0],prim.y[0],prim.x[1],prim.y[1]);
		glDisable(GL_BLEND);
		break;
	};
	glPopMatrix();
	if(next)
		next->draw(fnt);
}

