/*
 AGI Emulator for The Web - runtime.js
 Copyright (c) 2006 AntÃ³nio Afonso (aadsm@rnl.ist.utl.pt)
 
 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 Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/

/*
 AGI Emulator for The Web - runtime.js
 Copyright (c) 2006 António Afonso (aadsm@rnl.ist.utl.pt)

 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 Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/
//////////////////////////////////////
// AGI Runtime Functions
//////////////////////////////////////

var ERROR_NO_FUNCTIONS = 'No functions found in server.';
var ERROR_MISSING_OBJECT = 'Object is missing.';

var WORD_IGNORE = 0;
var WORD_ANY = 1;
var WORD_ROL = 9999;

var HAS_ITEM = 255;
var DROP_ITEM = 0;

/*
 * 09: has, inv
 */
function has( i1 )
{
	return core.inventory[i1].room == HAS_ITEM;
}

/*
 * 0A: obj.in.room, inv, num
 */
function obj_in_room( i1, n2 )
{
	return core.inventory[i1].room == n2;
}

/*
 * 0D: have.key
 */
function have_key()
{
	if ( core.have_key )
	{
		core.have_key = false;
		return true;
	}
	
	return false;
}

/*
 * 0E: said, num+
 *
 * - if f2 == 0 or f4 == 1, return FALSE.
 * Compare parameters W(i) and codes V(i) as follows:
 * - if W(i) = 1, it matches any V(i);
 * - if W(i) = 9999, it matches the whole remaining input i.e. the codes V(i), V(i+1),...V(m).
 * Otherwise W(i) should be equal to V(i).
 * If all elements match, f4 (said accepted the user input) is set to 1 and the 
 * command returns TRUE. Otherwise, FALSE is returned.
 */
function said()
{
	if ( !$f[2] || $f[4] )
	{
		return false;
	}
	
	var i = 0;
	for ( ; i < arguments.length; i++ )
	{
		var w = core.words[$w[i+1]];
		var v = core.words[arguments[i]];
		
		if ( v == WORD_ROL )
		{
			break;
		}
		
		if (  w != v && w != WORD_ANY )
		{
			return false;
		}
	}
	
	// check to see if all input words were matched
	if ( $w.length-1 > i && v != WORD_ROL )
	{
		return false;
	}
	
	//alert( $w + "\n\n" + arguments );
	$f[4] = true;
	return true;
}

/*
 * 0B: posn, obj, num, num, num, num
 */
function posn( o1, n2, n3, n4, n5 )
{
	if ( o1.x >= n2 && o1.x <= n4
		&& o1.y >= n3 && o1.y <= n5 )
	{
		return true;
	}
	else
	{
		return false;
	}
}

/*
 * 0C: controller, cont
 */
function controller( c1 )
{	
	if ( $c[c1] )
	{
		$c[c1] = false;
		return true;
	}
	
	return false;
	/*
	if ( core.key_pressed == 0 )
	{
		return false;
	}
	
	if ( $c[c1] <= 0xff )
	{
		return core.key_pressed == $c[c1];
	}
	
	var hiscan = $c[c1]>>8;
	
	switch ( core.key_pressed )
	{
		case KEY_ALT_X: return hiscan == 45;
	}
	
	// other non-obvious (at least for me) key scans.
	if ( $c[c1] == 0x0101 && core.key_pressed == KEY_ESC )
	{
		return true;
	}
	
	return core.key_pressed == $c[c1];
	*/
}

/*
 * 12: new.room, num
 */
function new_room( n1 )
{
	// 1- Commands stop.update and unanimate are issued to all objects;
	unanimate_all();
	for ( var i = 0; i < core.more_buffer.length; i++ )
	{
		core.more_buffer[i].erase();
	}
	core.more_buffer = new Array();
	// 3- Command player.control is issued;
	player_control();
	// 5 - set.horizon(36) command is issued;
	set_horizon( DEFAULT_HORIZON );
	// 6 - v1 is assigned the value of v0; v0 is assigned n (or the value of vn 
	//     when the command is new.room.v); v4 is assigned 0; v5 is assigned 0; 
	//     v16 is assigned the ID number of the VIEW resource that was associated
	//     with Ego (the player character).
	$v[1] = $v[0];
	$v[0] = n1;
	$v[4] = 0;
	$v[5] = 0;
	$v[9] = 0;
	// f2 - the player has issued a command line.
	$f[2] = false;
	if ( $o[0] && $o[0].view )
	{
		$v[16] = $o[0].view.number;
	}
	// 7 - Logic(i) resource is loaded where i is the value of v0 !
	load_logics( $v[0] );
	// 8 - Set Ego coordinates according to v2:
	//     - if Ego touched the bottom edge, put it on the horizon;
	//     - if Ego touched the top edge, put it on the bottom edge of the screen;
	//     - if Ego touched the right edge, put it at the left and vice versa.
	switch ( $v[2] )
	{
		case BORDER_SOUTH: $o[0].y = core.horizon+1; break;
		case BORDER_NORTH: $o[0].positionBottomEdge(); break;
		case BORDER_EAST: $o[0].x = 0; break;		
		case BORDER_WEST: $o[0].positionRightEdge(); break;
	}
	// 9 - v2 is assigned 0 (meaning Ego has not touched any edges).
	$v[2] = NO_BORDER;
	// 10 - f5 is set to 1 (meaning in the first interpreter cycle after the 
	//      new_room command all initialization parts of all logics loaded and 
	//      called from the initialization part of the new room's logic will be 
	//      called. In the subsequent cycle f5 is reset to 0
	$f[5] = true;
	// 11* - clear text screen
	textScreen.clear();
	status_line_update();
	close_msgbox();
	// 12* - reset print behaviour
	$f[15] = false;
	
	core.new_room = true;
	//alert( 'new.room( ' + n1 + '), f6: ' + $f[6] + ' v0: ' + $v[0] );
}

/*
 * 14: load.logics, num
 */
function load_logics( n1 )
{
	//alert( 'Loading logic' + n1 + '...' );
	// check previous load
	if( core.logics[n1] )
	{
		return;
	}
	
	var request = http_request();
	var url = 'agi.php?logic=' + n1;
	request.open( 'GET', url, false );
	request.send( null );
	
	var xml = request.responseXML;
	var logic = xml.getElementsByTagName( 'logic' );
	
	if ( logic == null )
	{
		//TODO: show error msg
		alert( 'no logic' );
		return -1;
	}
	
	var functions = xml.getElementsByTagName( 'function' );
	if ( functions == null )
	{
		//TODO: show error msg
		alert( ERROR_NO_FUNCTIONS + ': ' + n1 );
		return -1;
	}
	
	// DAJ (Dynamic Augmentation of Javascript)
	core.logics[n1] = new Array();
	core.logics[n1].start = 0;
	
	if ( functions.length == 0 )
	{
		alert( ERROR_NO_FUNCTIONS + ': ' + n1 );
		return -1;
	}
	
	for ( var i = 0; i < functions.length; i++ )
	{
		/*
		if ( functions.item(i).childNodes.length < 2 )
		{
			//TODO: show error msg
			return -1;
		}
		*/
		var func_n = functions.item(i).attributes.getNamedItem( 'number' ).nodeValue;
		var func;
		// IE puts CDATA on the 0 index, all other browsers on index 1
		if ( functions.item(i).childNodes.length > 1 )
		{
			func = functions.item(i).childNodes[1].data
		}
		else
		{
			func = functions.item(i).childNodes[0].data
		}
		try {
			eval( func );
		} catch (e) {
			alert( "[AGI: Error loading function]\n" + func + "\n\n" + e );
		}
		eval( "core.logics[n1][func_n] = logic" + n1 + "_" + func_n );
	}
	
	// load logic messages
	eval( "core.logics[n1]['messages']();" );
	//alert( 'Finished loading logic' + n1 + '...' );
}

/*
 * 16: call, num
 */
function call( n1 )
{
	var discard = false;
	// load logics if needed, then discard it
	if ( typeof( core.logics[n1] ) == 'undefined' /*|| core.logics[n1] == null*/ )
	{
		load_logics( n1 );
		discard = true;
	}
	
	// save state
	$m = core.logics[n1].m;
	
	stack.push( n1, core.logics[n1].start );
	
	var state = run_stack();
	
	// if the logic was left in a print waiting state, the we leave this function
	// imediatly to wait for a keypress, and then resume in the same stack frame.
	// remember that after a call statement there's always a return.
	if ( state == PRINT_WAITING || state == INPUT_WAITING )
	{
		return;
	}
	
	// load state
	stack.pop();
	$m = core.logics[stack.getLogic()].m;
	
	if ( discard )
	{
		discard_logics( n1 );
	}
}

/*
 * 18: load.pic, num
 */
function load_pic( n1 )
{
	if ( core.picture[n1] ) { return; }
	
	var request = http_request();
	var url = 'agi.php?picture=' + n1;
	/*
	 * Synchronous don't need this (using this function makes firefox acting
	 * like if it is an asynchronous call)
	request.onreadystatechange = function()
	{
		if ( request.readyState != 4 ) return;
		if ( request.status != 200 ) alert( PROBLEM_WITH_SERVER );
		core.picture[v1] = request.responseXML;
	}
	*/
	request.open( 'GET', url, false );
	request.send( null );
	
	core.picture[n1] = request.responseXML;
}

/*
 * 19: draw.pic, var
 */
function draw_pic( v1 )
{
	// clear add.to.pic elements
	for ( var i = 0; i < core.more_buffer.length; i++ )
	{
		core.more_buffer[i].erase();
	}
	core.more_buffer = new Array();
	
	core.buffer = core.picture[v1];
	
	// Load control lines
	var layers = core.buffer.getElementsByTagName( 'layer' );
	if ( layers.item(layers.length-1).firstChild
			&& layers.item(layers.length-1).attributes.getNamedItem( 'band' ).nodeValue == 'control_data' )
	{
		var line = layers.item(layers.length-1).getElementsByTagName( 'line' );
		core.control_lines = new Array( line.length );
		
		for ( var i = 0; i < line.length; i++ )
		{
			core.control_lines[i] = line.item( i ).firstChild.data;
		}
	}
	else
	{
		alert( MISSING_CONTROL_LINES );
	}
}

/*
 * 1A: show.pic, var
 */
function show_pic()
{
	var xml = core.buffer;
	
	// clear all layers
	for ( var i = 4; i < 16; i++ )
	{
		var img = document.getElementById( 'layer' + i );
		img.src = '';
		img.style.visibility = 'visible';
	}
	
	var layers = xml.getElementsByTagName( 'layer' );
	for ( var i = 0; i < layers.length-1; i++ )
	{
		var band = layers.item(i).attributes.getNamedItem( 'band' ).nodeValue;
		var src = layers.item(i).firstChild.data;
		var img = document.getElementById( 'layer' + band );
		img.src = src;
	}
	
	// hide empty layers
	for ( var i = 4; i < 16; i++ )
	{
		var img = document.getElementById( 'layer' + i );
		if ( img.src.indexOf( '.png' ) == -1 )
		{
			img.style.visibility = 'hidden';
		}
	}
}
/*
 * 1B: discard.pic, num
 */
function discard_pic( n1 )
{
	delete core.picture[n1];
}

/*
 * 1E: load.view, num
 */
function load_view( n1 )
{
	if ( core.view[n1] ) { return; }
	
	var request = http_request();
	var url = 'agi.php?view=' + n1;
	
	request.open( 'GET', url, false );
	request.send( null );
	
	core.view[n1] = new View( request.responseXML );
	
	/*
	if ( n1 == 89 )
		alert( "load_view: width: " + core.view[89].images[1][0]._width + "; height: " + core.view[89].images[1][0]._height );
	*/
}

/*
 * 20: discard.view, num
 */
function discard_view( n1 )
{
	delete core.view[n1];
}

/*
 * 21: animate.obj, num(obj)
 */
function animate_obj( n1 )
{
	core.objects[core.objects.length] = n1;
}

/*
 * 22: unanimate.all
 */
function unanimate_all()
{
	for ( var i = 0; i < $o.length; i++ )
	{
		$o[i].erase();
		$o[i].recycle();
	}
	core.objects = new Array();
}

/*
 * 23: draw, obj
 */
function draw( o1 )
{
	o1.show();
	// must force a draw because this object can be issued a stop.update command
	// before the cycle ends.
	o1.draw();
}

/*
 * 24: erase, obj
 */
function erase( o1 )
{
	o1.erase();
}

/*
 * 25: position, obj, num, num
 */
function position( o1, n2, n3 )
{
	o1.positionTo( n2, n3 );
}

/*
 * 27: get.posn, obj, num, num
 */
function get_posn( o1, n2, n3 )
{
	$v[n2] = o1.x;
	$v[n3] = o1.y;
}

/*
 * 28: reposition, obj, num, num
 */
function reposition( o1, n2, n3 )
{
	o1.x += n2;
	o1.y += n3;
	o1.moveOnce();
}

/*
 * 29: set.view, obj, num
 */
function set_view( o1, n2 )
{
	o1.setView( n2 );
}

/*
 * 2B: set.loop, obj, num
 */
function set_loop( o1, n2 )
{
	o1.setLoop( n2 );
}

/*
 * 2D: fix.loop, obj
 */
function fix_loop( o1 )
{
	o1.automatic_loop = false;
}

/*
 * 2E: release.loop, obj
 */
function release_loop( o1 )
{
	o1.automatic_loop = true;
}

/*
 * 2F: set.cel, obj, num
 */
function set_cel( o1, n2 )
{
	o1.setCell( n2 );
}

/*
 * 31: last.cel, obj, num
 */
function last_cel( o1, n2 )
{
	$v[n2] = o1.view.cells[o1.loop]-1;
}

/*
 * 32: current.cel, obj, num(var)
 */
function current_cel( o1, n2 )
{
	$v[n2] = o1.cell;
}

/*
 * 33: current.loop, obj, num(var)
 */
function current_loop( o1, n2 )
{
	$v[n2] = o1.loop;
}

/*
 * 34: current.view, obj, num(var)
 */
function current_view( o1, n2 )
{
	$v[n2] = o1.view.number;
}

/*
 * 36: set.priority, obj, num
 */
function set_priority( o1, n2 )
{
	o1.priority = n2;
	o1.automatic_priority = false;
}

/*
 * 38: release.priority, obj
 */
function release_priority( o1 )
{
	o1.automatic_priority = true;
	o1.calculatePriority();
}

/*
 * 3A: stop.update, num(obj)
 */
function stop_update( n1 )
{
	core.objects = core.objects.remove( n1 );
}

/*
 * 3B: start.update, num(obj)
 */
function start_update( n1 )
{
	if ( !core.objects.exists( n1 ) )
	{
		core.objects[core.objects.length] = n1;
	}
}

/*
 * 3C: force.update, obj
 */
function force_update( o1 )
{
	o1.draw();
}

/*
 * 3D: ignore.horizon, obj
 */
function ignore_horizon( o1 )
{
	o1.observe_horizon = false;
}

/*
 * 3E: observe.horizon, obj
 */
function observe_horizon( o1 )
{
	o1.observe_horizon = true;
}

/*
 * 3F: set.horizon, obj
 */
function set_horizon( n1 )
{
	core.horizon = n1;
}

/*
 * 40: object.on.water, obj
 */
function object_on_water( o1 )
{
	o1.surface = ON_WATER;
}

/*
 * 41: object.on.land, obj
 */
function object_on_land( o1 )
{
	o1.surface = ON_LAND;
}

/*
 * 42: object.on.anything, obj
 */
function object_on_anything( o1 )
{
	o1.surface = ON_ANYTHING;
}

/*
 * 43: ignore.objs, obj
 */
function ignore_objs( o1 )
{
	o1.observe_objs = false;
}

/*
 * 44: observe.objs, obj
 */
function observe_objs( o1 )
{
	o1.observe_objs = true;
}

/*
 * 45: distance, obj, obj, num(var)
 */
function distance( o1, o2, n3 )
{
	if ( !o1.on_screen || !o2.on_screen ) { return false; }
	$v[n3] = Math.abs(o1.x - o2.x) + Math.abs(o1.y - o2.y);
}

/*
 * 46: stop.cycling, obj
 */
function stop_cycling( o1 )
{
	o1.cycling = false;
}

/*
 * 47: start.cycling, obj
 */
function start_cycling( o1 )
{
	o1.cycling = true;
}

/*
 * 49: end.of.loop, obj, num(flag)
 */
function end_of_loop( o1, n2 )
{
	o1.endOfLoop( n2 );
}

/*
 * 4B: reverse.loop, obj, num(flag)
 */
function reverse_loop( o1, n2 )
{
	o1.reverseLoop( n2 );
}

/*
 * 4C: cycle.time, obj, num
 */
function cycle_time( o1, n2 )
{
	o1.cycle_time = n2;
}

/*
 * 4D: stop.motion, obj
 */
function stop_motion( o1 )
{
	o1.direction = STOP;
}

/*
 * 4E: start.motion, obj
 */
function start_motion( o1 )
{
	if ( !core.objects.exists( o1.number ) )
	{
		core.objects[core.objects.length] = o1.number;
	}
	
	if ( o1.number == 0 )
	{
		core.player_control = true;
	}
}

/*
 * 4F: step.size, obj, num
 */
function step_size( o1, n2 )
{
	if ( !o1 )
	{
		if ( DEBUG ) alert( stack.logic + 'step.size: ' + ERROR_MISSING_OBJECT );
		return;
	}
	o1.step_size = n2;
}

/*
 * 50: step.time, obj, num
 */
function step_time( o1, n2 )
{
	o1.step_time = n2;
}

/*
 * 51: move.obj, obj, num, num, num, num(flag)
 */
function move_obj( o1, n2, n3, n4, n5 )
{
	o1.moveObj( n2, n3, n4, n5 );
}

/*
 * 53: follow.ego, obj, num, num
 */
function follow_ego( o1, n2, n3 )
{
	o1.followEgo( n2, n3 );
}

/*
 * 54: wander, obj
 */
function wander( o1 )
{
	o1.wander();
}

/*
 * 55: normal.motion, obj
 */
function normal_motion( o1 )
{
	o1.normalMotion();
}

/*
 * 56: set.dir, obj, num
 */
function set_dir( o1, n2 )
{
	o1.direction = n2;
}

/*
 * 57: get.dir, obj, num
 */
function get_dir( o1, n2 )
{
	$v[n2] = o1.direction;
}

/*
 * 58: ignore.blocks, obj
 */
function ignore_blocks( o1 )
{
	o1.observe_blocks = false;
}

/*
 * 59: observe.blocks, obj
 */
function observe_blocks( o1 )
{
	o1.observe_blocks = true;
}

/*
 * 5A: block, num, num, num, num
 */
function block( n1, n2, n3, n4 )
{
	core.block.x1 = n1;
	core.block.y1 = n2;
	core.block.x2 = n3;
	core.block.y2 = n4;
	core.block.active = true;
}

/*
 * 5B: unblock
 */
function unblock()
{
	core.block.active = false;
}

/*
 * 5C: get, inv
 */
function get( i1 )
{
	core.inventory[i1].room = HAS_ITEM;
}

/*
 * 5E: drop, inv
 */
function drop( i1 )
{
	core.inventory[i1].room = DROP_ITEM;
}

/*
 * 62: load.sound, num
 */
function load_sound( n1 )
{
}

/*
 * 63: sound, num, num(flag)
 */
function sound( n1, n2 )
{
}

/*
 * 64: stop.sound, num
 */
function stop_sound( n1 )
{
}

/*
 * 65: print, msg
 */
function print( m1 )
{
	var msg = parse_message( m1 );
	var len = msg.length;
	
	len = calculate_word_wrap( msg, 32 );
	
	open_msgbox( msg, len, -1, -1 );
	
	// Message window is closed when ENTER or ESC key are pressed.
	if ( !$f[15] )
	{
		core.waiting_keypressed = true;
	}
}

/*
 * 67: display, num, num, msg
 */
function display( n1, n2, m3 )
{
	var msg = parse_message( m3 );
	textScreen.display( msg, n2, n1 );
}

/*
 * 69: clear.lines, num, num, num
 */
function clear_lines( n1, n2, n3 )
{
	textScreen.clearLines( n1, n2, n3 );
}

/*
 * 6A: text.screen
 */
function text_screen()
{
	//textScreen.clearScreen();
	textScreen.textMode();
}

/*
 * 6C: set.cursor.char, string
 */
function set_cursor_char( s1 )
{
	core.cursor = s1;
}

/*
 * 6D: set.text.attribute, num, num
 */
function set_text_attribute( n1, n2 )
{
	textScreen.fgcolor = n1;
	textScreen.bgcolor = n2;
}

/*
 * 6E: shake.screen, num
 */
function shake_screen( n1 )
{
	//TODO: implementations
}

/*
 * 6F: configure.screen, num, num, num
 */
function configure_screen( n1, n2, n3 )
{
	textScreen.setInput( n2 );
	textScreen.setStatus( n3 );
}

/*
 * 70: status.line.on
 */
function status_line_on()
{
	textScreen.status_on = true;
	status_line_update();
	//core.status_line.style.visibility = 'visible';
}

/*
 * 70,5: status.line.update
 */
function status_line_update()
{
	if ( !textScreen.status_on ) { return; }
	
	var score = 'Score:' + $v[3] + ' of ' + $v[7];
	var sound = 'Sound:' + ($f[9] ? 'on' : 'off' );
	//alert( "score: " + score + "\nsound: " + sound );
	/*
	var num_spaces = STATUS_LINE_COLS - score.length - sound.length;
	
	core.status_line.innerHTML = score.replace( /\s+/g, '&nbsp;' )
								+ "&nbsp;".repeat(num_spaces)
								+ sound.replace( /\s+/g, '&nbsp;' );
	*/
	textScreen.clearLines( textScreen.status_y, textScreen.status_y, 15 );
	textScreen.display( score, 1, textScreen.status_y, 0, 15 );
	textScreen.display( sound, 30, textScreen.status_y, 0, 15 );
}

/*
 * 71: status.line.off
 */
function status_line_off()
{
	//core.status_line.style.visibility = 'hidden';
	textScreen.status_on = false;
	textScreen.clearLines( textScreen.status_y, textScreen.status_y, textScreen.bgcolor );
}

/*
 * 72: set.string, num, string
 */
function set_string( n1, s2 )
{
	$s[n1] = s2;
}

/*
 * 73: get.string, num(var), msg, num, num, num
 */
function get_string( n1, m2, n3, n4, n5 )
{
	textScreen.getString( n1, m2, n4, n3, n5 );
}

/*
 * 75: parse, str
 */
function parse( s1 )
{
	parse_input( s1 );
}

/*
 * 76: get.num, msg, num(var)
 */
function get_num( m1, n2 )
{
	textScreen.getNum( m1, n2 );
}

/*
 * 77: prevent.input
 */
function prevent_input()
{
	core.input.style.visibility = 'hidden';
	core.accept_input = false;
}

/*
 * 78: accept.input
 */
function accept_input()
{
	core.input.style.visibility = 'visible';
	core.prompt = $s[0];
	core.accept_input = true;
	core.input.innerHTML = core.prompt + core.cursor;
}

/*
 * 79: set.key, num, num, num
 */
function set_key( n1, n2, n3 )
{
	//$c[n3] = n2<<8|n1;
	core.keys[n2<<8|n1] = n3;
}

/*
 * 7A: add.to.pic, num, num, num, num, num, num, num
 */
function add_to_pic( n1, n2, n3, n4, n5, n6, n7 )
{
	var obj = new AGIObject( BIT_OF_PICTURE );
	
	set_view( obj, n1 );
	set_loop( obj, n2 );
	set_cel( obj, n3 );
	//position( obj, n4, n5 );
	obj.x = n4;
	obj.y = n5;
	if ( n6 == 0 )
	{
		this.automatic_priority = true;
	}
	else
	{
		set_priority( obj, n6 );
	}
	
	if ( n7 < 4 )
	{
		
	}
	 
	core.more_buffer[core.more_buffer.length] = obj;
	
	obj.draw();
	obj.show();
}

/*
 * 7C: status
 */
function status()
{
	inventory.enable();
}

/*
 * 7D: save.game
 */
function save_game()
{
	alert( 'Sorry folks, not implemented yet :(' );
}

/*
 * 7E: restore.game
 */
function restore_game()
{
	alert( 'Sorry folks, not implemented yet :(' );
}

/*
 * 80: restart.game
 */
function restart_game()
{
	print( "Press ENTER to restart the game.\n\nPress ESC to continue this game." );
	//$f[6] = true;
	core.restart = true;
	core.waiting_keypressed = true;
}

/*
 * 81: show.obj, num
 */
function show_obj( n1 )
{
	load_view( n1 );
	// show description
	print( core.view[n1].description );
	// show object
	var obj = new AGIObject( INVENTORY_PICTURE );
	obj.setView( n1 );
	set_priority( obj, 15 );
	var x = (GAME_WIDTH-obj.width())/2;
	// the object must be shown in the bottom of the screen.
	//               (GAME_HEIGHT/3) - obj.height()
	// GAME_HEIGHT - ------------------------------
	//                               2
	var y = 5/6*GAME_HEIGHT + obj.height()/2;
	position( obj, x, y );
	draw( obj );
	
	core.inventory_obj = obj;
	core.inventory_showing = true;
}

/*
 * 82: random, num, num, num
 */
function random( n1, n2, n3 )
{
	var range = n2-n1+1;
	$v[n3] = Math.floor( Math.random() * range ) + n1;
}

/*
 * 83: program.control
 */
function program_control()
{
	core.player_control = false;
}

/*
 * 84: player.control
 */
function player_control()
{
	core.player_control = true;
}

/*
 * 86: quit, num
 */
function quit( n1 )
{
	if ( n1 == 0 )
	{
		print( "Press ENTER to quit.\nPress ESC to keep playing." );
		core.waiting_keypressed = true;
	}
	core.quit = true;
}

/*
 * 88: pause
 */
function pause()
{
	print( "      Game paused.      \nPress Enter to continue." );
	core.waiting_keypressed = true;
}

/*
 * 8A: cancel.line
 */
function cancel_line()
{
	textScreen.clearInput();
}

/*
 * 8F: set.game.id msg
 */
function set_game_id( m1 )
{
	core.game_id = m1;
}

/*
 * 91: set.scan.start
 */
function set_scan_start( part )
{
	core.logics[stack.getLogic()].start = part;
}

/*
 * 92: reset.scan.start
 */
function reset_scan_start()
{
	core.logics[stack.getLogic()].start = 0;
}

/*
 * 93: reposition.to, obj, num, num
 */
function reposition_to( o1, n2, n3 )
{
	o1.repositionTo( n2, n3 );
}

/*
 * 96: trace.info, num, num, num
 */
function trace_info( n1, n2, n3 )
{
	//TODO: implementations
}

/*
 * 97: print.at, msg, num, num,num
 */
function print_at( m1, n2, n3, n4 )
{
	var msg = parse_message( m1 );

	if ( n4 > TEXT_COLS )
	{
		n4 = calculate_word_wrap( msg, 32 );
	}
	
	open_msgbox( msg, n4, n2, n3 );
	
	// Message window is closed when ENTER or ESC key are pressed.
	if ( !$f[15] )
	{
		core.waiting_keypressed = true;
	}
}

/*
 * 9A: clear.text.rect, num, num, num, num, num
 */
function clear_text_rect( n1, n2, n3, n4, n5 )
{
	textScreen.clearRectangle( n2, n1, n4, n2, n5 );
}

/*
 * 9C: set.menu, msg
 */
function set_menu( m1 )
{
	menu.addMenu( m1 );
}

/*
 * 9D: set.menu.item, msg, num
 */
function set_menu_item( m1, n2 )
{
	menu.addMenuItem( m1, n2 );
}

/*
 * 9E: submit.menu
 */
function submit_menu()
{
}

/*
 * A0: disable.item, cont
 */
function disable_item( c1 )
{
	$c[c1] = DISABLED_ITEM;
}

/*
 * A1: menu.input
 */
function menu_input()
{
	menu.enable();
}

/*
 * A9: close.window
 */
function close_window()
{
	close_msgbox();
}

/*
 * discard.logics, num
 */
function discard_logics( n1 )
{
	//core.logics[n1] = null;
	delete core.logics[n1];
}


/*
 * ALTERNATIVE
 */
function assignn( n1, n2 )
{
	$v[n1] = n2;
}

/*
 * DEBUG
 */
function show_state()
{
	alert( "[AGI: Interperter State]\n\n" + stack );/*+ "\n"
		+ $o[0] + "\n\nv38:" + $v[38] + " v39:" + $v[39] 
		+ "\nv40:" + $v[40] + " v41:" + $v[41] 
		+ "\nv6:" + $v[6] + " f35:" + $f[35] );*/
}

