//	Magnetron
//	Copyright (C)1997,1999,2001 Stephen Battey

//	written by Stephen Battey for the Amstrad CPC464 - 1993

//	re-written for the Internet - March 1997
//	http://www.aston.ac.uk/~batteysp/

//	re-written for Netscape v4 - February & March 1999
//	http://www.geocities.com/steve-e-b

//	modified for NS4, IE4 - March & April 2001
//	http://www.truplex.com/debugged/






//************************************************
//			Global Variables
//************************************************



//*******************  Image Data  *******************


ImageLoaded = 0		//	Number of the image currently being downloaded
SeqBaseImg = 0;		//	Index of the first image in the sequence
PitBaseImg = 0;		//	Index of the first image in the pit

//	Array of images to be loaded
ImageName = new Array("BlueTriangle.gif", "BlueSquare.gif", "BlueCircle.gif", "RedTriangle.gif", "RedSquare.gif", "RedCircle.gif", "YellowTriangle.gif", "YellowSquare.gif", "YellowCircle.gif", "GreenTriangle.gif", "GreenSquare.gif", "GreenCircle.gif", "PinkTriangle.gif", "PinkSquare.gif", "PinkCircle.gif", "CyanTriangle.gif", "CyanSquare.gif", "CyanTriangle.gif", "WhiteTriangle.gif", "WhiteSquare.gif", "WhiteCircle.gif", "Rock.gif", "Light.gif", "Weight.gif", "BlackDot.jpg", "Bomb.gif", "Detonator.gif", "Blank.gif", "TopMag.gif", "LeftMag.gif", "RightMag.gif", "Explosion1.gif", "Explosion2.gif", "Explosion3.gif", "Explosion4.gif", "Explosion5.gif", "Explosion6.gif", "Explosion7.gif", "Explosion8.gif", "Explosion9.gif", "Explosion10.gif", "Flux.gif", "DarkRock.gif", "Pixel.gif")




//**********************  Pre-Game Settings  *******************


LastPuzz = NoOfDemos	//	Index of highest puzzle player has reached
FirstPuzzSetting = 0	//	Index of first puzzle selected
DiffSetting = 1		//	Index of difficulty selected


GameState = null		//	Stores the current status of the game
				//	 0 - loading images
				//	 1 - prompt sequence
				//	 2 - prepare sequence
				//	 3 - game playing
				//	 4 - pusling
				//	 5 - mid-air (lifting/dropping)
				//	 6 - end of level sequence
				//	 7 - exploding
				//	 8 - game over sequence
				//	 9 - demo running


PromptTimer = null	//	Display sequence of pre-game instructions
PrepareTimer = null	//	Display sequence of Ready Set Go messages
CounterTimer = null	//	Keeps track of the game time
RockTimer = null		//	Times the appearing & disappearing of rocks
PulseTimer = null		//	To handle sliding of boxes as they are dragged
MidAirTimer = null	//	To handle the lifting and dropping of boxes
MovingOutTimer = null	//	Handles moving a wanted box to the side of the screen
CongratTimer = null	//	Animate completed message
GameOverTimer = null	//	Animate game over message
KeyCheckTimer = null	//	Processes actions for keys held down
DemoTimer = null		//	To run demo actions
BonusClearTimer = null	//	Remove bonus display after a delay
DetonationTimer = null	//	Animate detonation of a bomb

DetonateRow = null;
DetonateCol = null;
DetonateState = null;

InMidAir = false		//	Flags when a drag command is waiting to occur
BonusShown = false	//	Flags when a bonus value is shown in the AddScore box
MovingOutPos = 0		//	Position of the box being moved out, 0 for no box being moved out
ControlEditMode = false	//	Flags when user exits standard prompt state into set control state


//	Store default position of each letter in the COMPLETED message
CompletedFraction = new Array(1, 0.7627,  0.50508,  0.17288, -0.05084, -0.28813, -0.52542, -0.76271, -1)


//	Sine & Cosine values for the angular positions of the game over letters as they spiral up
GameOverAngleSin = new Array(0, 0.986281128, 0.914663638, 0.650411038, 0.325619404, 0, -0.29537659, -0.544329738, -0.739443026, -0.878778314, -0.963902533, -0.998614096, -0.988081605, -0.938244008, -0.855385872, -0.745834829, -0.615746897, -0.470956448, -0.316874498, -0.158423521, 0)

GameOverAngleCos = new Array(1, 0.165074336, -0.404215821, -0.759582439, -0.945500927, -1, -0.955380903, -0.838871346, -0.673219141, -0.477230211, -0.266255342, -0.052629717, 0.153930964, 0.34597425, 0.517991322, 0.666130924, 0.787944007, 0.882156463, 0.948467476, 0.987371251, 1)




//**********************  Game Settings  ********************


Score = null		//	Score for the current game
StartLevelNo = null	//	Number of the level player started at (0,1,2,...)
GameDiff = null		//	Difficulty of this game
ScoreMulti = null	//	Score factor (based on difficulty)
NewDiffOpened = null	//	Flag set when the game has opened a new difficulty setting


//	Array of names for each difficulty
DiffNames = new Array( "Practice", "Easy", "Normal", "Hard" );


//	Array of names for each difficulty
DiffGameIds = new Array( null, 17, 18, 19 );


//	Array of multipliers that increase score based on difficulty
ScoreMultipliers = new Array( 0, 1, 2, 4, 8 );


//	Delay in ms between dragging boxes & letting them drop
DragDropDelay = new Array(800, 800, 350, 150, 100)


//	Delay for in-game rocks to hide & appear (merge with above ??)
RockStateDelay = new Array(800, 800, 500, 350, 275)




//*********************  Level Settings  ********************


Boxes = new Array()		//	2D array of image file names
for (i=1; i<9; i++)
	Boxes[i] = new Array()


NoOfRocks = null			//	Number of in-game rocks
RockRowPos = new Array()	//	Row position of in-game rocks
RockColPos = new Array()	//	Column position of in-game rocks
RockOutDelay = new Array()	//	Time that rock is hidden
RockInDelay = new Array()	//	Time that rock is shown
RockTime = new Array()		//	Time left before rock changes state (-ve hidden, +ve shown)


LevelNo = null			//	Number of current level (0,1,2,...)
BoxValue = null			//	Points awarded for removing a box from this level
NoOfMoves = null			//	The number of moves taken for this level
LevelTimeM	= null		//	Minutes left to complete scene
LevelTimeS	= null		//	Seconds left to complete scene

TopMagPos = null			//	Position of the top magnet
SideMagPos = null			//	Position of the side magnets

GotStr = null			//	Image file name of block held by top magnet

NextBoxIndex = null		//	The index of the box to be removed from the scene
NextBoxImage = null		//	The image file name of the box to be removed from the scene
NextBoxLeft = null		//	Number of these boxes left in the scene

PulseDir = null			//	Direction of the current pulse
FirstPulseCol = null		//	First column to be moved in the current pulse

FoundFlux = null			//	Flags if flux is found when searching for a box below a given position




//**********************  Hi-Score Table Data  ********************


BestScore = new Array()		//	Array of presonal best scores with score, day, date, month & year attributes


//	An array of day names
dayName = new Array("Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday")

//	An array of month names
monthName = new Array("January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December")


var HiScorePos = 0;




//*************************  Key Data  *******************


//	indicies for keys: 0 - k   - top magnet left
//				 1 - l   - top magnet right
//				 2 - s   - side magnets up
//				 3 - x   - side magnets down
//				 4 - SPC - top magnet on/off
//				 5 - a   - pulse left side magnet
//				 6 - ;   - pulse right side magnet
//				 7 - q   - quit

//	Key codes - stores the ascii codes for the control keys
KeyCode = new Array(107, 108, 115, 120, 32, 97, 59, 113)

//	Key press states - stores length of time depressed (-1 for not depressed)
KeyState = new Array(-1, -1, -1, -1, -1, -1, -1, -1)


//	Key press listener
function MagnetronKeyListener()
{
	this._super();
	this.notify_down = key_down;
	this.notify_up = key_up;
}
MagnetronKeyListener.JSFC__superClasses = new Array( DualEventListener );
MagnetronKeyListener.JSFC__methods = new Array(	"notify_down",
						"notify_up" );


//	List of ascii characters to convert key codes to characters
AsciiList = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~£"




//***********************  Demo Game Data  **********************


DemoLevel = -1		//	Current demo game playing (-1 for no demo running)
DemoState = null		//	Current stage in the demo game


//	List of actions used in the demo game
DemoActionSeq = new Array()
DemoActionSeq[0] = new Array(-1,-1,2,6,0,0,4,0,4,5,1,1,1,1,4,1,4,0,0,0,4,0,0,0,4)
DemoActionSeq[1] = new Array(1,1,4,2,2,5,0,-1,4,1,1,4,3,5,0,0,0,4,6,-1,-1,5,-1,0,4)
DemoActionSeq[2] = new Array(2,2,5,1,1,1,4,0,0,0,0,0,0,2,5,4,-1,-1,3,3,6,1,-1,4,1,1,4,1,4,1,4)
DemoActionSeq[3] = new Array(-1,-1,0,0,0,0,4,1,1,1,1,1,1,4,2,2,5,0,0,0,2,2,2,2,2,6,4,-1,4,1,1,1,4, -1,-1,-1,-1, 3,3,3,3,3,6,-1,1,  4,0,4,3,5,-1,1,-1,-1,-1,-1,-1,-1,-1,-1,4)







//************************************************
//			Utility Functions
//************************************************


function round(number)
//		Function returns the extracted integer part
//		 of a decimal number - Math.round is not used
//		 since it is only availiable on a Unix platform
{
	v=number.toString()
	dp=v.indexOf(".")

	if ( dp==-1 )
		return number
	if ( ( dp==0 ) | ( v.substring(0,dp)=="-" ) )
		return 0

	return eval(v.substring(0,dp))
}



function num_text(v, width, use)
//		Returns the number 'v' in a text string of minimum
//		 length 'width', preceeding spaces being filled with
//		 the character specified in 'use'
{
	post=v.toString()
	pre=""
	uselen=width-post.length
	for (i=1; i<=uselen; i++)
		pre+=use

	return pre+post
}




function best_score(score, dayIndex, date, monthIndex, year)
//		Used when declaring a new entity for the hi-score table
{
	this.score = score
	this.day   = dayIndex
	this.date  = date
	this.month = monthIndex
	this.year  = year
}







//**************************************************
//			Cookie Routines
//**************************************************


function save_game_data()
//		Stores control keys, level number & hiscores to a cookie
{
	//	construct data string
	dataString = ""

	//	insert key chars
	var index;
	for (keyIndex=0; keyIndex<8; keyIndex++)
		dataString += KeyCode[keyIndex] + " ";

	//	insert last puzzle number
	dataString += LastPuzz + " ";

	//	insert first puzzle setting
	dataString += FirstPuzzSetting + " ";

	//	insert difficulty setting
	dataString += DiffSetting

	//	insert hi scores
	for (scoreIndex=0; scoreIndex<BestScore.length; scoreIndex++)
		dataString += " " + BestScore[scoreIndex].score + " " + BestScore[scoreIndex].day + " " + BestScore[scoreIndex].date + " " + BestScore[scoreIndex].month + " " + BestScore[scoreIndex].year


	//	save cookie to expire in 1 years time
	expDate = new Date()
	expDate.setTime( expDate.getTime() + (365*24*60*60*1000) )
	document.cookie = "Magnetron99=" + escape(dataString) + "; expires=" + expDate.toGMTString()
}




function load_game_data()
//		Retrieves the control keys, level number & hiscores from a cookie
{
	//	check if cookie exists
	if ( document.cookie.length>0 )
	{
		//	check if Magnetron data is stored
		offset = document.cookie.indexOf("Magnetron99=")
		if ( offset!=-1 )
		{
			//	find start position of data
			offset += 12
			end = document.cookie.indexOf(";", offset)
			if ( end==-1 )
				end = document.cookie.length

			dataString = unescape(document.cookie.substring(offset, end))
			readIndex = 0

			//	decode keys
			var dataChar;
			for (keyIndex=0; keyIndex<8; keyIndex++)
				KeyCode[keyIndex] = read_next_number();

			//	read last puzzle
			LastPuzz = read_next_number()

			//	read first puzzle setting
			FirstPuzzSetting = read_next_number()

			//	read difficulty setting
			DiffSetting = read_next_number()

			//	read hi scores
			scoreIndex = 0
			while ( readIndex<dataString.length )
				BestScore[scoreIndex++] = new best_score(read_next_number(), read_next_number(), read_next_number(), read_next_number(), read_next_number())
		}
	}
}


function read_next_number()
//		For load_game_data - read & return number following readIndex in dataString
{
	spaceIndex = readIndex + 1;
	while ( ( dataString.charAt(spaceIndex)!=" " ) & ( spaceIndex<dataString.length ) )
		spaceIndex++;

	value = parseInt( dataString.substring(readIndex, spaceIndex) );

	readIndex = spaceIndex + 1;

	return value;
}






//*****************************************************
//			Screen Output Functions
//*****************************************************


function show_moves()
//		Displays number of moves taken
{
	document.UserOpts.Moves.value = num_text(NoOfMoves, 5, " ")
}




function show_score()
//		Displays the score for this game
{
	document.UserOpts.Score.value = num_text(Score, 8, " ")
}




function show_time()
//		Displays the time left to complete the scene
{
	document.UserOpts.Time.value = num_text(LevelTimeM, 2, " ") + ":" + num_text(LevelTimeS, 2, "0")
}




function show_side_mags()
//		Displays the two side magnets
{
	ImNo = (SideMagPos*14) + 43 + PitBaseImg
	document.images[ImNo].src = "LeftMag.gif"
	document.images[ImNo+11].src = "RightMag.gif"
}




function hide_side_mags()
//		Removes the two side magnets
{
	ImNo = (SideMagPos*14) + 43 + PitBaseImg
	document.images[ImNo].src = "BlackDot.jpg"
	document.images[ImNo+11].src = "BlackDot.jpg"
}




function show_top_mag()
//		Displays the top magnet
{
	document.images[TopMagPos+PitBaseImg+14].src = "TopMag.gif"
	document.images[TopMagPos+PitBaseImg+28].src = GotStr
}




function hide_top_mag()
//		Removes the top magnet
{
	document.images[TopMagPos+PitBaseImg+14].src = "BlackDot.jpg"
	document.images[TopMagPos+PitBaseImg+28].src = "BlackDot.jpg"
}




function show_tile(row, col)
//		Refreshes the tile at the given row & column
{
	ImNo = (row*14) + 44 + PitBaseImg + col
	document.images[ImNo].src = Boxes[row][col]
}




function show_next_box_image()
//		Display the next box to be removed at side of pit
{
	document.images[PitBaseImg+28].src = NextBoxImage
	document.images[PitBaseImg+41].src = NextBoxImage
}




function set_seq_box(seqNo, seqImg)
//		Displays the sequence box
{
	document.images[seqNo+SeqBaseImg].src = seqImg
}




function update_puzzle_list()
//		Extends the level list when new levels are accessed
{
	for (i=document.UserOpts.Level.options.length; i<=LastPuzz-NoOfDemos; i++)
	{
		newLevel = new Option("")
		document.UserOpts.Level.options[i] = newLevel
		document.UserOpts.Level.options[i].text = "Level "+(i+1)
	}
}




function update_diff_list()
//		Extends difficulty list when user reaches given ability
{
	if (LastPuzz == HardDiffPuzz)
	{
		newDiff = new Option("Hard");
		document.UserOpts.Diff.options[3] = newDiff;
		NewDiffOpened = true;
	}
	if (LastPuzz == ArghDiffPuzz)
	{
		newDiff = new Option("Argghh");
		document.UserOpts.Diff.options[4] = newDiff;
		NewDiffOpened = true;
	}
}



function show_level_number( ypos )
{
	DynDocs.levelnum.write_dhtml( "<table width=422><td align=center><font size=4 color='#d0ffff'>LEVEL " + (LevelNo-NoOfDemos+1) + "</font></td></table>" );
	DynDocs.levelnum.move_to( PitXPos, ypos );
	DynDocs.levelnum.set_display( true );
}






//************************************************
//			Low-Level Functions
//************************************************


function count_up(thisImg)
//		Scans the boxes left in the scene and return the number of
//		 occurances of this image file name
{
	count=0

	for (c=1; c<9; c++)
		for (r=1; r<9; r++)
			if ( Boxes[r][c]==thisImg )
				count++

	return count
}




function next_to_get()
//		Removes the current wanted box from the sequence display
//		 and refreshes the side panel with the image of the required box
{
	//	remove currently wanted box from sequence display
	if ( NextBoxIndex>-1)
		set_seq_box(NextBoxIndex, "Blank.gif")

	//	until all boxes are removed
	while ( NextBoxIndex<21 )
	{
		//	move onto next box in sequence,
		//	 get its image file name and number left in scene
		NextBoxIndex++
		NextBoxImage = ImageName[NextBoxIndex]
		NextBoxLeft = count_up(NextBoxImage)

		//	exit loop if some boxes of this type are in the scene
		if ( NextBoxLeft>0 )
			break
	}
}




function set_sequence()
//		Shows the boxes that need collecting in the sequence display
{
	for (sqBox=0; sqBox<21; sqBox++)
	{
		if ( count_up(ImageName[sqBox])==0 )
			set_seq_box(sqBox, "Blank.gif")
		else
			set_seq_box(sqBox, ImageName[sqBox])
	}
}




function next_below(c, r)
//		Calculates the row index of the next block
//		 directly below the row specified in the 'c'th column
//		If flux lies between these positions the FoundFlux flag is set
{
	FoundFlux = false

	//	check if box below if empty stopping at the bottom row
	while ( ++r<9 )
	{
		if ( Boxes[r][c]=="Flux.gif" )
			FoundFlux = true
		else if ( Boxes[r][c]!="BlackDot.jpg" )
			break
	}

	return r
}




function set_playing_area()
//		Prepares the pit for the beginning of the level specified
{
	settingStr = OrgSetting[LevelNo]

	rowNo = 1
	colNo = 1

	//	run thro' each character in the setting string
	for (p=0; p<64; p++)
	{
		//	get box number from setting string
		boxNo = RelStr.indexOf(settingStr.charAt(p))

		//	set this image in the Boxes array
		Boxes[rowNo][colNo] = ImageName[boxNo]
		show_tile(rowNo, colNo)
		//	move onto next position in pit
		colNo++
		if ( colNo>8 )
		{
			colNo = 1
			rowNo++
		}
	}
}




function register_rock_data()
//		Store rock data from the level rock string to the rock data arrays
{
	NoOfRocks = (RockData[LevelNo].length)/7

	strInd = 0
	for (rockNo=0; rockNo<NoOfRocks; rockNo++)
	{
		RockRowPos[rockNo] = AsciiList.indexOf( RockData[LevelNo].charAt(strInd++) ) - 16;
		RockColPos[rockNo] = AsciiList.indexOf( RockData[LevelNo].charAt(strInd++) ) - 16;
		RockOutDelay[rockNo] = AsciiList.indexOf( RockData[LevelNo].charAt(strInd++) ) - 16;
		RockInDelay[rockNo] = AsciiList.indexOf( RockData[LevelNo].charAt(strInd++) ) - 16;
		RockTime[rockNo] = AsciiList.indexOf( RockData[LevelNo].charAt(strInd++) ) - 16;
		if ( eval(RockData[LevelNo].charAt(strInd++))==1 )
			RockTime[rockNo] = -RockTime[rockNo]
		strInd++

		if ( RockTime[rockNo]>0 )
		{
			if ( RockTime[rockNo]==1 )
				Boxes[RockRowPos[rockNo]][RockColPos[rockNo]] = "DarkRock.gif"
			else
				Boxes[RockRowPos[rockNo]][RockColPos[rockNo]] = "Rock.gif"
			show_tile(RockRowPos[rockNo], RockColPos[rockNo])
		}
	}
}




function update_time()
//		Call once a second during each level to update the time left to complete the puzzle
{
	//	send update timer off again with 1s delay
	CounterTimer = window.setTimeout("update_time()", 1000)

	//	decrease time left
	LevelTimeS--
	if ( LevelTimeS<0 )
	{
		if ( LevelTimeM==0 )
		{
			if ( GameState==3 )
				//	time-up, game over (otherwise wait for game state to return to 3)
				game_over(0)
			return
		}

		LevelTimeS = 59
		LevelTimeM--
	}

	show_time()
}




function update_rocks()
//		Hide, show in-game rocks
{
	//	send update timer off again with 1s delay
	RockTimer = window.setTimeout("update_rocks()", RockStateDelay[GameDiff])

	for (rockNo=0; rockNo<NoOfRocks; rockNo++)
	{
		if ( RockTime[rockNo]<0 )
		//	rock is hidden
		{
			RockTime[rockNo]++

			if ( RockTime[rockNo]==0 )
			{
				if ( Boxes[RockRowPos[rockNo]][RockColPos[rockNo]]=="BlackDot.jpg" )
				{
					//	add rock to scene
					if ( RockInDelay[rockNo]==1 )
							Boxes[RockRowPos[rockNo]][RockColPos[rockNo]] = "DarkRock.gif"
						else
							Boxes[RockRowPos[rockNo]][RockColPos[rockNo]] = "Rock.gif"
					show_tile(RockRowPos[rockNo], RockColPos[rockNo])
				}

				//	prepare to remove
				RockTime[rockNo] = RockInDelay[rockNo]
			}
		}
		else
		//	rock is shown
		{
			RockTime[rockNo]--

			if (  ( RockTime[rockNo]>0 )
			    & ( Boxes[RockRowPos[rockNo]][RockColPos[rockNo]]=="BlackDot.jpg" )  )
			{
				//	show rock
				Boxes[RockRowPos[rockNo]][RockColPos[rockNo]] = "Rock.gif"
				show_tile(RockRowPos[rockNo], RockColPos[rockNo])
			}
			else if (  ( RockTime[rockNo]==1 )
				   & (  ( Boxes[RockRowPos[rockNo]][RockColPos[rockNo]]=="Rock.gif" )
					| ( Boxes[RockRowPos[rockNo]][RockColPos[rockNo]]=="BlackDot.jpg" )  )  )
			{
				//	darken rock
				Boxes[RockRowPos[rockNo]][RockColPos[rockNo]] = "DarkRock.gif"
				show_tile(RockRowPos[rockNo], RockColPos[rockNo])
			}
			else if ( RockTime[rockNo]==0 )
			{
				if ( Boxes[RockRowPos[rockNo]][RockColPos[rockNo]]=="DarkRock.gif" )
				{
					//	remove rock from scene
					Boxes[RockRowPos[rockNo]][RockColPos[rockNo]] = "BlackDot.jpg"
					show_tile(RockRowPos[rockNo], RockColPos[rockNo])

					if ( ( GameState==4 ) & ( RockRowPos[rockNo]==SideMagPos ) )
					{
						//	set position to flux
						Boxes[RockRowPos[rockNo]][RockColPos[rockNo]] = "Flux.gif"
						show_tile(RockRowPos[rockNo], RockColPos[rockNo])

						//	drag this column again
						InMidAir = true
						MidAirTimer = window.setTimeout("drag()", 40)
					}
					else
					{
						//	remove rock from scene
						Boxes[RockRowPos[rockNo]][RockColPos[rockNo]] = "BlackDot.jpg"
						show_tile(RockRowPos[rockNo], RockColPos[rockNo])
					}


					//	drop boxes in this column
					drop_column_down(RockRowPos[rockNo]-1, RockColPos[rockNo])
				}

				//	prepare to add
				RockTime[rockNo] = -RockOutDelay[rockNo]
			}
		}
	}
}




function add_to_score(value)
//		Adds the value given to the score
{
	//	increment & display score
	Score += value*ScoreMulti
	show_score()

	//	display value added, set to timeout
	if ( BonusShown )
		clearTimeout(BonusClearTimer)
	document.UserOpts.AddScore.value = "0" + ScoreMulti.toString() + "x" + value.toString()
	BonusClearTimer = window.setTimeout("remove_bonus_display()",1800)
	BonusShown = true
}




function make_move()
//		Decrease number of moves
{
	if ( NoOfMoves>0 )
	{
		NoOfMoves--
		show_moves()
	}


	//	Game over in hard mode if no moves are left but boxes are still in the pit
	if ( ( NoOfMoves==0 ) & ( GameDiff>2 ) & ( count_up(NextBoxImage)!=0 ) )
		window.setTimeout("game_over(0)", 300)
}




function remove_bonus_display()
//		Remove the bonus displayed & clear the timer flag
{
	document.UserOpts.AddScore.value = ""
	BonusShown = false
}






//************************************************
//			Action Functions
//************************************************


function side_mag_move(dir)
//		Move the side magnets to 'ToPos'
{
	//	action allowed only in game running or mid air states
	if ( ( GameState==3 ) | ( GameState==5 ) )
	{
		//	compute new position
		newPos = SideMagPos + dir

		//	check if new position is valid
		if ( ( newPos<1 ) | ( newPos>8 ) )
			return

		//	move magnets to new position
		hide_side_mags()
		SideMagPos = newPos
		show_side_mags()
	}
}




function top_mag_move(dir)
//			Move the over-head magnet
{
	//	action allowed only in game running or pulsing states
	if ( ( GameState==3 ) | ( GameState==4 ) )
	{
		//	check if movement is valid
		newPos = TopMagPos + dir
		if ( ( newPos<1 ) | ( newPos>12 ) )
			return

		//	move magnet
		hide_top_mag()
		TopMagPos = newPos
		show_top_mag()
	}
}




function throw_switch()
//			Switch the over-head magnet on/off
{
	//	only works if magnet is over the pit
	if ( ( TopMagPos<3 ) | ( TopMagPos>10 ) )
		return

	//	check if a box is current held
	if ( GotStr=="BlackDot.jpg" )
		pick_up()
	else
		drop_down()
}



function pick_up()
//		Pick up a box from the playing area
{
	//	search for box under magnet
	fromCol = TopMagPos - 2

	//	search for first non-rock under magnet
	toRow = 0
	while (true)
	{
		fromRow = next_below(fromCol, toRow)
		if ( fromRow==9 )
			//	empty column
			return

		if (  ( Boxes[fromRow][fromCol]!="Rock.gif" )
		    & ( Boxes[fromRow][fromCol]!="DarkRock.gif" ) )
			break

		toRow = fromRow
	}


	boxImg = Boxes[fromRow][fromCol]

	//	check this is an active box
	if (  ( boxImg==NextBoxImage )
	    | ( boxImg=="Light.gif" )
	    | ( boxImg=="Bomb.gif" )
	    | ( boxImg=="Detonator.gif" )  )
	{
		//	remove box from current position
		Boxes[fromRow][fromCol] = "BlackDot.jpg"
		show_tile(fromRow, fromCol)

		if ( FoundFlux )
		{
			//	place box in mid air
			Boxes[SideMagPos][fromCol] = boxImg
			show_tile(SideMagPos, fromCol)

			InMidAir = true
			GameState = 5
			MidAirTimer = window.setTimeout("drag()", 50)
		}
		else if ( toRow>0 )
		{
			//	place box into position below last rock
			toRow++
			Boxes[toRow][fromCol] = boxImg
			show_tile(toRow, fromCol)

			if ( ( fromRow==SideMagPos ) & ( GameState==4 ) )
			{
				//	box taken from dragged row, so re-drag
				InMidAir = true
				MidAirTimer = window.setTimeout("drag()", 40)
			}

			//	drop box after a delay
			window.setTimeout("drop_column_down("+toRow+", "+fromCol+")", 100)
		}
		else
		{
			//	place box under top magnet
			GotStr = boxImg
			show_top_mag()
			if ( GotStr=="Bomb.gif" )
			{
				//	move into exploding state
				GameState = 7
				ExplodeTimer = window.setTimeout("explode(0)", 20)
			}
			else if ( ( fromRow==SideMagPos ) & ( GameState==4 ) )
			{
				//	box taken from dragged row, so re-drag
				InMidAir = true
				MidAirTimer = window.setTimeout("drag()", 30)
			}


			//	check if box is one that is wanted
			if ( GotStr==NextBoxImage )
			{
				if ( DemoLevel==-1 )
					//	increase score
					add_to_score(BoxValue)

				//	register box being removed from scene
				NextBoxLeft--
				if ( NextBoxLeft==0 )
					//	search for next box to be removed
					next_to_get()

				//	check if another box is being slided
				if ( MovingOutPos>0 )
				{
					//	remove old box & timer
					document.images[MovingOutPos+PitBaseImg+28].src = "BlackDot.jpg"
					clearTimeout(MovingOutTimer)
					//	show next box image
					show_next_box_image()
				}

				//	prepare to move box out
				MovingOutPos = 0
				MovingOutTimer = window.setTimeout("move_box_out()", 40)
			}

		}

		make_move()
	}
}




function drop_down()
//		Procedure to drop a block from the over-head magnet
{
	//	search for space under magnet
	fromCol = TopMagPos - 2
	fromRow = next_below(fromCol, 0)

	//	if there's enough room in this column
	if ( fromRow>1 )
	{
		if ( FoundFlux )
		{
			//	place box into fluxed position
			Boxes[SideMagPos][fromCol] = GotStr
			show_tile(SideMagPos, fromCol)

			InMidAir = true
			GameState = 5
			MidAirTimer = window.setTimeout("drag()", 50)
		}
		else
		{
			//	place box into standard position
			Boxes[fromRow-1][fromCol] = GotStr
			show_tile(fromRow-1, fromCol)

			check_for_detonation(fromRow-1, fromCol)
		}

		//	remove box from under top magnet
		GotStr="BlackDot.jpg"
		show_top_mag()

		make_move()
	}
}




function drop_column_down(thisRow, thisCol)
//		Drop block at & those above the position given
{
	//	find where next box is below this one
	landedRow = next_below(thisCol, thisRow) - 1
	if ( FoundFlux )
		toRow = SideMagPos
	else
		toRow = landedRow

	noDropped = 0

	if ( toRow!=thisRow )
	{
		fromRow = thisRow

		//	while still in the pit
		while ( fromRow>0 )
		{
			//	stop when reaching top of column, a rock or a row currently being pulsed
			if (  ( Boxes[fromRow][thisCol]=="BlackDot.jpg" )
			    | ( Boxes[fromRow][thisCol]=="Rock.gif" )
			    | ( Boxes[fromRow][thisCol]=="DarkRock.gif" )
			    | ( Boxes[fromRow][thisCol]=="Flux.gif" )
			    | ( ( GameState==4 ) & ( fromRow==SideMagPos ) ) )
				break

			//	drop box down
			Boxes[toRow][thisCol] = Boxes[fromRow][thisCol]
			Boxes[fromRow][thisCol] = "BlackDot.jpg"
			show_tile(toRow, thisCol)
			show_tile(fromRow, thisCol)

			noDropped++
			fromRow--
			toRow--
		}
		Boxes[fromRow+1][thisCol] = "BlackDot.jpg"
		show_tile(fromRow+1, thisCol)
	}

	if ( noDropped>0 )
	{
		if ( FoundFlux )
		{
			InMidAir = true
			GameState = 5
			MidAirTimer = window.setTimeout("drag()", 50)
		}
		else
			//	boxes held by flux will not depress detonator
			check_for_detonation(landedRow, thisCol)

	}
}




function check_for_detonation(thisRow, thisCol)
//		Checks if the box at thisRow, thisCol has landed on a detonator linked to a bomb
{
	if (   (thisRow < 8) && (thisCol < 8)
	    && (Boxes[thisRow+1][thisCol+1] == "Bomb.gif")
	    && (Boxes[thisRow+1][thisCol] == "Detonator.gif")  )

			detonate( 0, thisRow, thisCol );
}



function detonate( state, thisRow, thisCol )
//		Runs detonation animation
{
	if (state == 0)
	{
		/* initialise detonation parameters */
		DetonateRow = thisRow;
		DetonateCol = thisCol;
		DetonateState = GameState;
		GameState = 5;

		/* position animation frames */
		var xPos = PitXPos + ( (DetonateCol+2) *30 );
		var yPos = PitYPos + ( (DetonateRow+3) *30 );
		for (i=0; i<10; i++)
			DynDocs.pitExplosion[i].move_to( xPos, yPos );
	}
	else
		/* hide previous animation frame */
		DynDocs.pitExplosion[state-1].set_display( false );

	/* perform last state actions */
	if (state == 10)
	{
		/* hide explosion images */
		for (i=0; i<10; i++)
			DynDocs.pitExplosion[i].set_display( false );

		/* drop down any boxes above the explosion */
		drop_column_down( (DetonateRow-1), DetonateCol );
		drop_column_down( (DetonateRow-1), (DetonateCol+1) );
		if (DetonateCol < 7)
			drop_column_down( (DetonateRow-1), (DetonateCol+2) );

		/* return to previous state */
		GameState = DetonateState;

		/* check if all target blocks have been destroyed */
		if (count_up( NextBoxImage ) == 0)
			next_to_get();

		return;
	}

	/* set timer to show next frame */
	DetonationTimer = window.setTimeout( "detonate(" + (state+1) + ")", 45 );

	/* display animation frame */
	DynDocs.pitExplosion[state].set_display( true );

	if (state == 5)
	{
		/* remove any adjacent boxes */
		Boxes[DetonateRow][DetonateCol] = "BlackDot.jpg";
		show_tile( DetonateRow, DetonateCol );
		Boxes[DetonateRow+1][DetonateCol] = "BlackDot.jpg";
		show_tile( DetonateRow+1, DetonateCol );
		Boxes[DetonateRow][DetonateCol+1] = "BlackDot.jpg";
		show_tile( DetonateRow, DetonateCol+1 );
		Boxes[DetonateRow+1][DetonateCol+1] = "BlackDot.jpg";
		show_tile( DetonateRow+1, DetonateCol+1 );

		if (DetonateRow < 7)
		{
			Boxes[DetonateRow+2][DetonateCol]="BlackDot.jpg";
			show_tile( DetonateRow+2, DetonateCol );
			Boxes[DetonateRow+2][DetonateCol+1]="BlackDot.jpg";
			show_tile( DetonateRow+2, DetonateCol+1 );
		}

		if (DetonateCol < 7)
		{
			Boxes[DetonateRow][DetonateCol+2]="BlackDot.jpg";
			show_tile( DetonateRow, DetonateCol+2 );
			Boxes[DetonateRow+1][DetonateCol+2]="BlackDot.jpg";
			show_tile( DetonateRow+1, DetonateCol+2 );
		}

		if ( (DetonateRow < 7) & (DetonateCol < 7) )
		{
			Boxes[DetonateRow+2][DetonateCol+2]="BlackDot.jpg";
			show_tile( DetonateRow+2, DetonateCol+2 );
		}
	}
}






//*************************************************
//			Top-Level Functions
//*************************************************


function setup()
//		Setup procedure
{
	//	listen for key events
	KeyEventRouter.singleton().add_listener( new MagnetronKeyListener() );

	for (var i=0; i<document.images.length; i++)
	{
		if (typeof( document.images[i].name ) != "undefined")
		{
			if (document.images[i].name == "SeqFImg")
				SeqBaseImg = i;
			if (document.images[i].name == "PitFImg")
				PitBaseImg = i;
		}
	}

	//	get hi-scores and controls from cookie
	load_game_data()

	//	initialise level select pull-down menu
	document.UserOpts.Level.options[0].text = "Level 1"
	update_puzzle_list()
	document.UserOpts.Level.selectedIndex = FirstPuzzSetting

	//	initialise difficulty pull-down menu
	update_diff_list()
	document.UserOpts.Diff.selectedIndex = DiffSetting

	//	display control key for selected action
	display_action_key()

	// display the 'sequence' text
	DynDocs.sequence.set_display( true );

	// set the state to accept loading of images
	GameState = 0;

	// register a handler for loading of images
	EventMonitor.agent( document.images["loader"], EventMonitor.LOAD ).add_listener( load_images );

	ImageLoaded = 0;
	load_images();
}

/*
 * Register the setup routine to be called once the document has loaded.
 */
var DocLoadEvent = EventMonitor.agent( window, EventMonitor.LOAD );
DocLoadEvent.add_listener( setup );




function load_images()
//		Load images required for the game
{
	if ( ImageLoaded==ImageName.length )
	{
		//	start prompt sequence
		DynDocs.loading.set_display( false )
		GameState = 1
		PromptTimer = window.setTimeout("prompt_text(0)", 50)
	}
	else
		//	load next image, this must be done as a timeout otherwise IE loads the image
		//	direct and causes a recursive loop!!
		setTimeout( "document.images['loader'].src = ImageName[ImageLoaded++]", 5 );
}




function prompt_text(state1)
//		Display sequence of pre-game messages
{
	if ( state1==72 )
		//	wrap round to beginning
		state1 = 0


	//	flash "Click Here" text
	if ( state1/8==round(state1/8) )
		DynDocs.clickhere.set_display( true )
	else if ( (state1+3)/8==round((state1+3)/8) )
		DynDocs.clickhere.set_display( false )


	switch (state1)
	{
		case 1:	DynDocs.scores.set_display( false ); break
		case 3:	DynDocs.play.set_display( true ); break
		case 25:	DynDocs.play.set_display( false ); break
		case 27:	DynDocs.demo.set_display( true ); break
		case 49:	DynDocs.demo.set_display( false ); break
		case 51:	DynDocs.scores.set_display( true ); break
	}

	//	re-call for next message state
	PromptTimer = window.setTimeout("prompt_text("+(state1+1)+")", 100)
}




function start_game()
//		Set up global variables and timers for the start of a new game
{
	//	hide text from previous state
	if ( GameState==1 )
	{
		clearTimeout(PromptTimer)
		DynDocs.clickhere.set_display( false )
		DynDocs.play.set_display( false )
		DynDocs.demo.set_display( false )
		DynDocs.scores.set_display( false )
	}
	else
	{
		clearTimeout(GameOverTimer)
		for (i=0; i<8; i++)
			DynDocs.gameover[i].set_display( false )
		DynDocs.newhiscore.set_display( false )
	}


	//	get number of first level & difficulty
	GameDiff = DiffSetting

	NewDiffOpened = false;

	StartLevelNo = FirstPuzzSetting + NoOfDemos
	if (   (GameDiff == 0)
	    && (StartLevelNo >= NoOfPractices)  )
		StartLevelNo = NoOfPractices - 1;		// limit practice level

	LevelNo = StartLevelNo

	//	compute score multiplier
	ScoreMulti = ScoreMultipliers[GameDiff]

	//	initialise score
	Score = 0
	show_score()

	start_level()
}




function start_level()
//		Setup variables and screen ready for play to begin
{
	if ( DemoLevel==-1 )
	{
		//	check if this level is players best
		if ( LevelNo>LastPuzz )
		{
			LastPuzz = LevelNo
			update_puzzle_list()
			update_diff_list()
		}
	}
	else
	//	this is a demo game
	{
		if ( LevelNo>=NoOfDemos )
		{
			//	demo wraps round to first level
			LevelNo = 0
			DemoLevel = 0
		}
		DemoState = 0
	}


	//	setup the playing area & sequence display
	set_playing_area()
	set_sequence()


	GotStr = "BlackDot.jpg"
	TopMagPos = 7
	show_top_mag()

	SideMagPos = 8
	show_side_mags()

	//	find first box to be removed
	NextBoxIndex = -1
	next_to_get()
	show_next_box_image()

	//	calculate value for removing a box from this level
	BoxValue = (LevelNo+1)*10

	//	set initial time
	if (GameDiff == 0)
	{
		// ignore time in practice games
		LevelTimeM = 0;
		LevelTimeS = 0;
	}
	else
	{
		LevelTimeM = StartTimeM[LevelNo][GameDiff-1]
		LevelTimeS = StartTimeS[LevelNo][GameDiff-1]
	}
	show_time()

	//	import in-game rocks
	register_rock_data()

	//	set moves limit
	NoOfMoves = StartMoves[LevelNo]
	show_moves()


	//	Set no keys as being pressed
	for (i=0; i<7; i++)
		KeyState[i] = -1


	//	move into prepare prompt state
	GameState = 2
	PrepareTimer = window.setTimeout("ready_set_go(0)", 20)
}




function ready_set_go(state2)
//		Flashes up the ready, steady go strings
{
	switch (state2)
	{
		case 0:
			show_level_number( PitYPos + 72 );
			DynDocs.ready.set_display( true )
			PrepareTimer = window.setTimeout("ready_set_go(1)", 1200)
			break
		case 1:
			DynDocs.ready.set_display( false )
			DynDocs.set.set_display( true )
			PrepareTimer = window.setTimeout("ready_set_go(2)", 900)
			break
		case 2:
			DynDocs.levelnum.set_display( false );
			DynDocs.set.set_display( false )
			DynDocs.go.set_display( true )
			PrepareTimer = window.setTimeout("ready_set_go(3)", 2000)
			GameState = 3
			KeyCheckTimer = window.setTimeout("key_check()", 50)
			RockTimer = window.setTimeout("update_rocks()", RockStateDelay[GameDiff])

			// start count down on all non-practice games
			if (GameDiff > 0)
				CounterTimer = window.setTimeout("update_time()", 1000)

			//	begin demo if demo was selected
			if ( DemoLevel>-1 )
				DemoTimer = window.setTimeout("demo_game()", 500)

			break
		case 3:
			DynDocs.go.set_display( false )
			break
	}
}




function drag()
//		Drag boxes across in line with the side magnets
{
	moveToCol = FirstPulseCol
	thisCol = FirstPulseCol
	endCol = FirstPulseCol + (8*PulseDir)

	//	for each column
	while ( thisCol!=endCol )
	{
		//	fill blank spaces with the magnetic flux image
		if ( ( Boxes[SideMagPos][thisCol]=="BlackDot.jpg" ) | ( Boxes[SideMagPos][thisCol]=="Flux.gif" ) )
			Boxes[SideMagPos][thisCol]="Flux.gif"
		else
		{
			held = false;

			/* check if this box if being held down */
			if (   (SideMagPos > 1)
			    && (Boxes[SideMagPos-1][thisCol] != "BlackDot.jpg")
			    && (Boxes[SideMagPos-1][thisCol] != "Rock.gif")
			    && (Boxes[SideMagPos-1][thisCol] != "DarkRock.gif")  )
				held = true;

			/* check if this box is a rock (and therefore should remain where it is) */
			if (   (Boxes[SideMagPos][thisCol] == "Rock.gif")
			    || (Boxes[SideMagPos][thisCol] == "DarkRock.gif")  )
				held = true;

			if ( held )
				//	subsequent boxes move next to this box
				moveToCol = thisCol + PulseDir
			else
			{
				//	move box if necessary
				if ( moveToCol!=thisCol )
				{
					Boxes[SideMagPos][moveToCol] = Boxes[SideMagPos][thisCol]
					Boxes[SideMagPos][thisCol] = "Flux.gif"
					show_tile(SideMagPos, moveToCol)
				}
				//	shift 'move to' position
				moveToCol += PulseDir
			}
		}

		//	refresh the tile at this position
		show_tile(SideMagPos, thisCol)

		//	move onto next column
		thisCol += PulseDir
	}


	if ( InMidAir )
		InMidAir = false
	else
	{
		//	start dropping the boxes
		PulseTimer = window.setTimeout("drop(false)", DragDropDelay[GameDiff])
	}
	GameState = 4
}




function drop(pulseKeyReleased)
//		Drop boxes down after being dragged
{
	if ( InMidAir )
	{
		//	box being lifted, discard extra drag command
		clearTimeout(MidAirTimer)
		InMidAir = false
	}

	if ( pulseKeyReleased )
		clearTimeout(PulseTimer)


	//	end of drag & drop state
	make_move()
	GameState = 3


	thisCol = FirstPulseCol + (7*PulseDir)
	endCol = FirstPulseCol - PulseDir

	//	for each column
	while ( thisCol!=endCol )
	{
		//	remove flux images
		if ( Boxes[SideMagPos][thisCol]=="Flux.gif" )
		{
			Boxes[SideMagPos][thisCol]="BlackDot.jpg"
			show_tile(SideMagPos, thisCol)
		}
		else
			//	drop boxes in this column
			drop_column_down(SideMagPos, thisCol)

		//	move onto next column
		thisCol -= PulseDir
	}
}




function move_box_out()
//		Slide the wanted box out to the side
{
	//	initial call, set position of box & remove it from top magnet
	if ( MovingOutPos==0 )
	{
		SlidingImage = GotStr
		GotStr = "BlackDot.jpg"

		MovingOutPos = TopMagPos
	}

	//	subsequent calls
	else
	{
		//	remove old box
		document.images[MovingOutPos+PitBaseImg+28].src = "BlackDot.jpg"

		if ( ( MovingOutPos==1 ) | ( MovingOutPos==12 ) )
		{
			//	box is now removed
			MovingOutPos = 0
			show_next_box_image()

			if ( NextBoxImage=="Rock.gif" )
				//	level is complete
				congrats(0)

			return
		}

		if ( MovingOutPos<7 )
			//	move left
			MovingOutPos--
		else
			//	move right
			MovingOutPos++

		document.images[MovingOutPos+PitBaseImg+28].src = SlidingImage
	}

	//	setup call for next state
	MovingOutTimer = window.setTimeout("move_box_out()", 37)
}




function congrats(state3)
//		Perfrom end of level (completed) routine
{
	//	check for springy lettering sequence
	if ( state3<18 )
	{
		angle = (state3/10)*Math.PI
		amplitude = ( (-8.75)*state3 ) + 147.5
		offset = 147.5 - amplitude*Math.cos(angle)

		//	compute position for each letter
		for (i=0; i<9; i++)
		{
			newPos = PitXPos + 195.5 - CompletedFraction[i]*offset
			DynDocs.completed[i].move_to(newPos, PitYPos+32)
		}


		//	check for initial state
		if ( state3==0 )
		{
			clearTimeout(CounterTimer)
			clearTimeout(KeyCheckTimer)
			clearTimeout(RockTimer)
			if ( GameState==4 )
				clearTimeout(PulseTimer)
			if ( InMidAir )
				clearTimeout(MidAirTimer)

			//	remove magnets
			hide_top_mag()
			hide_side_mags()

			GameState = 6

			//	show completed text
			show_level_number( PitYPos + 90 );
			DynDocs.levelnum.set_display( true );
			for (i=0; i<9; i++)
				DynDocs.completed[i].set_display( true )
		}

		//	re-call for next state
		CongratTimer = window.setTimeout("congrats("+(state3+1)+")", 40)
	}


	//	give completion bonus award
	else if ( state3==18 )
	{
		if (   (DemoLevel == -1)
		    && (GameDiff > 0)  )
		{
			DynDocs.compbonus.set_display( true )
			add_to_score( (LevelNo-NoOfDemos+1)*100 )
			CongratTimer = window.setTimeout("congrats(19)", 2200)
		}
		else
			//	in demo or practice, move straight to end of congrat sequence
			CongratTimer = window.setTimeout("congrats(20)", 2200)
	}


	//	check for time bonus award
	else if ( state3==19 )
	{
		DynDocs.compbonus.set_display( false )
		DynDocs.timebonus.set_display( true )
		add_to_score( (LevelTimeM*60)+LevelTimeS )
		CongratTimer = window.setTimeout("congrats(20)", 2200)
	}


	//	check for move count bonus
	else if ( state3==20 )
	{
		if ( NoOfMoves>0 )
		{
			DynDocs.timebonus.set_display( false )
			DynDocs.movebonus.set_display( true )
			add_to_score( NoOfMoves*BoxValue )
			CongratTimer = window.setTimeout("congrats(21)", 2200)
		}
		else
			//	continue straight onto end of sequence
			state3 = 21
	}


	//	check for end of sequence - catch run through from state 19
	if ( state3==21 )
	{
		//	hide completed text
		DynDocs.levelnum.set_display( false );
		for (i=0; i<9; i++)
			DynDocs.completed[i].set_display( false )
		DynDocs.timebonus.set_display( false )
		DynDocs.movebonus.set_display( false )

		//	compute number of next level
		LevelNo++
		if ( LevelNo==NoOfPuzzles )
			LevelNo = NoOfDemos

		if ( DemoLevel>-1 )
			//	move to next demo game
			DemoLevel++

		if (   ( LevelNo==StartLevelNo )
		    || (   (GameDiff == 0)
		    	&& (LevelNo == NoOfPractices)  )  )
			//	end of game
			game_over(0)
		else
			//	begin next level
			start_level()

		return
	}
}




function explode(n)
//		Animate bomb explosion
{
	n++

	if ( n<10 )
		//	set timer to show next frame
		ExplodeTimer = window.setTimeout("explode("+n+")", 45)


	//	initial step
	if ( n==1 )
	{
		//	set state
		GameState = 7

		//	remove magnet & bomb images
		document.images[TopMagPos+PitBaseImg+28].src = "BlackDot.jpg"
		document.images[TopMagPos+PitBaseImg+14].src = "BlackDot.jpg"

		//	position explosion image
		var xPos = PitXPos + (TopMagPos*30) - 25;
		var yPos = PitYPos + 30;
		for (i=0; i<10; i++)
			DynDocs.explosion[i].move_to( xPos, yPos );
	}
	else
		// hide previous animation frame
		DynDocs.explosion[n-1].set_display( false );


	if ( n<10 )
		//	animate explosion
		DynDocs.explosion[n].set_display( true )
	else
		//	move onto game over
		game_over(0)
}




function game_over(state4)
//		Perform game over routine
{
	if ( ( state4<45 ) & ( DemoLevel==-1 ) )
		GameOverTimer = window.setTimeout("game_over("+(state4+1)+")", 20)

	if ( state4==0 )
	{
		GameState = 8

		if ( DemoLevel>-1 )
		{
			//	catch demo if timers run out of sync
			end_demo()
			return
		}

		clearTimeout(CounterTimer)
		clearTimeout(KeyCheckTimer)
		clearTimeout(RockTimer)
		if ( GameState==4 )
			clearTimeout(PulseTimer)
		if ( InMidAir )
			clearTimeout(MidAirTimer)

		//	remove magnets
		hide_top_mag()
		hide_side_mags()

		//	position lettering
		for (i=0; i<4; i++)
			DynDocs.gameover[i].move_to(PitXPos+46, PitYPos+292)
		for (i=4; i<8; i++)
			DynDocs.gameover[i].move_to(PitXPos+341, PitYPos+292)

		//	check for hiscore
		//	HiScorePos will be used in state 46 to test if the hiscore alert text should be displayed
		if (Score == 0)
			HiScorePos = 10
		else
		{
			for (HiScorePos=0; HiScorePos<BestScore.length; HiScorePos++)
			{
				if ( Score>BestScore[HiScorePos].score )
					break
			}

			if ( HiScorePos<10 )
			{
				var startIndex = BestScore.length
				if ( startIndex==10 )
					//	for full table do not move down last score
					startIndex = 9

				/* slide down old scores */
				for (var i=startIndex; i>HiScorePos; i--)
					BestScore[i] = BestScore[i-1]

				/* insert new score */
				var now = new Date()
				BestScore[HiScorePos] = new best_score( Score,
									now.getDay(),
									now.getDate(),
									now.getMonth(),
									now.getFullYear() );

				save_game_data()
			}
		}
	}


	//	move G, R
	if ( ( state4>2 ) & ( state4<24 ) )
	{
		step = state4 - 3
		if ( step==0 )
		{
			DynDocs.gameover[0].set_display( true )
			DynDocs.gameover[7].set_display( true )
		}
		else
		{
			amp = 13*step
			xAmp = amp * GameOverAngleSin[step]
			yAmp = amp * GameOverAngleCos[step]

			DynDocs.gameover[0].move_to(PitXPos+46-xAmp, PitYPos+292-yAmp)
			DynDocs.gameover[7].move_to(PitXPos+341+xAmp, PitYPos+292-yAmp)
		}
	}


	//	move A, E
	if ( ( state4>9 ) & ( state4<31 ) )
	{
		step = state4 - 10
		if ( step==0 )
		{
			DynDocs.gameover[1].set_display( true )
			DynDocs.gameover[6].set_display( true )
		}
		else
		{
			amp = 13*step
			xAmp = amp * GameOverAngleSin[step]
			yAmp = amp * GameOverAngleCos[step]

			DynDocs.gameover[1].move_to(PitXPos+46-xAmp+(1.9*step), PitYPos+292-yAmp)
			DynDocs.gameover[6].move_to(PitXPos+341+xAmp-(1.7*step), PitYPos+292-yAmp)
		}
	}


	//	move M, V
	if ( ( state4>16 ) & ( state4<38 ) )
	{
		step = state4 - 17
		if ( step==0 )
		{
			DynDocs.gameover[2].set_display( true )
			DynDocs.gameover[5].set_display( true )
		}
		else
		{
			amp = 13*step
			xAmp = amp * GameOverAngleSin[step]
			yAmp = amp * GameOverAngleCos[step]

			DynDocs.gameover[2].move_to(PitXPos+46-xAmp+(3.7*step), PitYPos+292-yAmp)
			DynDocs.gameover[5].move_to(PitXPos+341+xAmp-(3.5*step), PitYPos+292-yAmp)
		}
	}


	//	move E, O
	if ( ( state4>23 ) & ( state4<45 ) )
	{
		step = state4 - 24
		if ( step==0 )
		{
			DynDocs.gameover[3].set_display( true )
			DynDocs.gameover[4].set_display( true )
		}
		else
		{
			amp = 13*step
			xAmp = amp * GameOverAngleSin[step]
			yAmp = amp * GameOverAngleCos[step]

			DynDocs.gameover[3].move_to(PitXPos+46-xAmp+(6*step), PitYPos+292-yAmp)
			DynDocs.gameover[4].move_to(PitXPos+341+xAmp-(5.25*step), PitYPos+292-yAmp)
		}
	}



	switch ( state4 )
	{
		case 45:
			//	end of anim delay
			GameOverTimer = window.setTimeout("game_over(46)", 500)
			break

		case 46:
			//	display hiscore alert if hiscore was made
			var delay = 1000;

			if (HiScorePos < 10)
			{
				DynDocs.newhiscore.set_display( true );
				delay += 1000
			}

			if (NewDiffOpened)
			{
				DynDocs.newDiff.set_display( true );
				delay += 750;
			}

			GameOverTimer = window.setTimeout( "game_over(47)", delay );
			break;

		case 47:
			//	end of game over sequence
			//	hide game over text
			for (i=0; i<8; i++)
				DynDocs.gameover[i].set_display( false )
			DynDocs.newhiscore.set_display( false )
			DynDocs.newDiff.set_display( false )

			//	remove boxes
			for (r=1; r<9; r++)
			{
				for (c=1; c<9; c++)
				{
					Boxes[r][c] = "BlackDot.jpg"
					show_tile(r, c)
				}
			}
			
			// submit score to the hi-scores database
			if (   (Score > 0)
			    && (DiffGameIds[GameDiff] != null)
			    && (promptSubmitScore)  )
			{
				var levelsStr;
				if (LevelNo == StartLevelNo)
					levelsStr = "Level " + (LevelNo-NoOfDemos+1);
				else
					levelsStr = "Levels " + (StartLevelNo-NoOfDemos+1) + ".." + (LevelNo-NoOfDemos+1);
				
				var scores = new Array();
				scores[0] = new HiScore( 7, Score, DiffNames[GameDiff] );
				scores[1] = new HiScore( DiffGameIds[GameDiff], Score, levelsStr );

				promptSubmitScore( scores );
			}

			//	begin prompting for next game
			GameState = 1
			prompt_text(0)
			break
	}
}




function start_demo()
//		Set up global variables and timers for the start of a demo game
{
	//	hide text from previous state
	if ( GameState==1 )
	{
		clearTimeout(PromptTimer)
		DynDocs.clickhere.set_display( false )
		DynDocs.play.set_display( false )
		DynDocs.demo.set_display( false )
		DynDocs.scores.set_display( false )
	}
	else
	{
		clearTimeout(GameOverTimer)
		for (i=0; i<8; i++)
			DynDocs.gameover[i].set_display( false )
		DynDocs.newhiscore.set_display( false )
	}


	//	show demo sign
	DynDocs.demoalert.set_display( true )


	//	set level number & difficulty
	StartLevelNo = -1
	LevelNo = 0
	GameDiff = 2

	//	initialise score
	Score = 0
	show_score()

	DemoLevel = 0
	start_level()
}




function demo_game()
//		Controls the demo game
{
	if (   (DemoActionSeq[DemoLevel].length <= DemoState)
	    || (GameState < 3)
	    || (GameState > 5)  )
		//	end of demo level, no more actions
		return;
	else
	{
		if (   ( (DemoLevel == 2) && (DemoState == 14) )
		    || ( (DemoLevel == 3) && (DemoState == 25) ) )
			/* quick move required */
			DemoTimer = window.setTimeout( "demo_game()", 50 );
		else
			DemoTimer = window.setTimeout( "demo_game()", 250 );
	}

	/* flash 'press any key' sign */
	if ((DemoState/3) == round(DemoState/3))
		DynDocs.demokey.set_display( false );
	else
		DynDocs.demokey.set_display( true );

	/* perform action on this state */
	key_action(DemoActionSeq[DemoLevel][DemoState]);

	/* move onto next action */
	DemoState++;
}




function end_demo()
//		Clear up after demo
{
	//	clear demo timers
	clearTimeout(DemoTimer)
	DemoLevel = -1

	//	clear game timers
	clearTimeout(KeyCheckTimer)
	clearTimeout(CounterTimer)
	clearTimeout(RockTimer)
	if ( GameState==4 )
		clearTimeout(PulseTimer)

	//	hide demo text
	DynDocs.demoalert.set_display( false )
	DynDocs.demokey.set_display( false )

	//	remove magnets
	hide_side_mags()
	hide_top_mag()

	GameState = 1
	PromptTimer = window.setTimeout("prompt_text(0)",1000)
}






//*****************************************************
//			Key Control Functions
//*****************************************************


function key_action(keyIndex)
//		Performs the action for a given key
{
	//	do not allow movement or pulsing of side magnets when pulsing
	if (  ( GameState==4 )  &  ( ( keyIndex>1 ) & ( keyIndex!=4 ) )  )
		return

	//	do not allow any action when box is in mid air
	if ( GameState==5 )
		return

	//	allow quit only in normal game mode
	if ( ( GameState!=3 ) & ( keyIndex==7 ) )
		return

	switch (keyIndex)
	{
		case 0:
			top_mag_move(-1)
			break
		case 1:
			top_mag_move(1)
			break
		case 2:
			side_mag_move(-1)
			break
		case 3:
			side_mag_move(1)
			break
		case 4:
			throw_switch()
			break
		case 5:
			FirstPulseCol = 1
			PulseDir = 1
			drag()
			break
		case 6:
			FirstPulseCol = 8
			PulseDir = -1
			drag()
			break
		case 7:
			game_over(0)
			break
	}
}




function key_down(key)
//		Handles the pressing of a key
{
	//	accept key to edit control
	if ( ControlEditMode )
		key_change(key)


	//	accept key commands to exit demo
	else if ( ( DemoLevel>-1 ) & ( ( GameState>2 ) & ( GameState<6 ) ) )
		end_demo()


	//	accept pre-game key commmands
	else if ( ( GameState==1 ) | ( GameState==8 ) )
	{
		if ( ( key==112 ) | ( key==80 ) )
			start_game()
		else if ( ( key==100 ) | ( key==68 ) )
			start_demo()
		else if ( ( key==104 ) | ( key==72 ) )
			show_hiscores()
	}


	//	accept in-game key commands
	else if ( ( GameState>2 ) & ( GameState<6 ) )
	{
		for (keyIndex=0; keyIndex<8; keyIndex++)
		{
			if ( key==KeyCode[keyIndex] )
			{
				key_action(keyIndex)
				KeyState[keyIndex] = 0
			}
		}
	}
}




function key_up(key)
//		Handles the release of a key
{
	for (keyIndex=0; keyIndex<8; keyIndex++)
		if ( key==KeyCode[keyIndex] )
			KeyState[keyIndex] = -1

	//	release of pulse key (in pulse mode), drop dragged boxes
	if (  ( ( GameState==4 ) | ( GameState==5 ) )  &  ( ( key==KeyCode[5] ) | ( key==KeyCode[6] ) )  )
		drop(true)
}




function key_check()
//		Called periodically during a level to checks if any movement keys are depressed
{
	KeyCheckTimer = window.setTimeout("key_check()",50)

	for (keyIndex=0; keyIndex<4; keyIndex++)
	{
		if ( KeyState[keyIndex]>-1 )
		{
			KeyState[keyIndex]++
			if ( KeyState[keyIndex]>5 )
				key_action(keyIndex)
		}
	}
}




function display_action_key()
//		Displays the key ascii value - or code - in the box specified
{
	key = KeyCode[document.UserOpts.Control.selectedIndex]

	if ( key==32 )
		document.UserOpts.Key.value = "SPC"
	else if ( key==13 )
		document.UserOpts.Key.value = "RET"
	else if ( key==8 )
		document.UserOpts.Key.value = "BS"
	else
		document.UserOpts.Key.value = String.fromCharCode( key );
//		document.UserOpts.Key.value = AsciiList.charAt( key-32 );
}




function key_change(newKey)
//		Checks & validates the key stored in the 'boxRef' input box in the controls form,
//		 storing the valid value in the keyRef inde xof the key array
{
	selectedKeyIndex = document.UserOpts.Control.selectedIndex

	//	assume key is unused, run through other keys to check it is not used
	unused = true
	for (keyIndex=0; keyIndex<8; keyIndex++)
		if ( keyIndex!=selectedKeyIndex )
			if ( newKey==KeyCode[keyIndex] )
				unused = false

	if (unused)
	{
		//	set new key to this action
		KeyCode[selectedKeyIndex] = newKey
		save_game_data()

		//	move focus back to action menu
		document.UserOpts.Control.focus()
	}
	else
	{
		DynDocs.keyalert.set_display( true )
		window.setTimeout("DynDocs.keyalert.set_display( false )",1500)
	}

	//	update key displayed (with delay so it comes after browser updates value with users keypress)
	window.setTimeout("display_action_key()",50)
}




function control_selection(action)
//		Stop or start
{
	if ( GameState==1 )
	{
		if ( ControlEditMode )
		{
			if ( action=="off" )
			{
				DynDocs.keychange.set_display( false )

				prompt_text(0)

				ControlEditMode = false
			}
		}
		else
		{
			if ( action=="on" )
			{
				clearTimeout(PromptTimer)
				DynDocs.clickhere.set_display( false )
				DynDocs.play.set_display( false )
				DynDocs.demo.set_display( false )
				DynDocs.scores.set_display( false )

				DynDocs.keychange.set_display( true )

				ControlEditMode = true
			}
		}
	}
	else
		window.setTimeout("display_action_key()", 50)
}




function key_reset()
//		Reset the control keys back to default values
{
	KeyCode[0] = 107
	KeyCode[1] = 108
	KeyCode[2] = 115
	KeyCode[3] = 120
	KeyCode[4] = 32
	KeyCode[5] = 97
	KeyCode[6] = 59
	KeyCode[7] = 113
	display_action_key()
	save_game_data()
}




function save_setting()
//		Store the first level & difficluty setting
{
	FirstPuzzSetting = document.UserOpts.Level.selectedIndex
	DiffSetting = document.UserOpts.Diff.selectedIndex

	save_game_data()
}






//*****************************************************
//			HTML production code
//*****************************************************


function draw_pit_grid()
//		Writes the HTML code for the images that construct the pit
{
	var pitSetupStr = "11111111111111100000000000011000000000000111100000000111101000000001011010000000010110100000000101101000000001011010000000010110100000000101101000000001011010000000010111111111111111"
	var strIndex = 0
	var baseName = " name='PitFImg'";

	for (var imgRow=0; imgRow<13; imgRow++)
	{
		for (var imgCol=0; imgCol<14; imgCol++)
		{
			imgFile = "BlackDot.jpg"
			if ( pitSetupStr.charAt( strIndex )=="1" )
				imgFile = "Rock.gif"

			document.write("<img src='"+imgFile+"' width=30 height=30" + baseName + ">")
			strIndex++;
			baseName = "";
		}
		document.write("<br>")
	}
}




function show_hiscores()
//		Write the hi-score table to new window
{
	hiScoreWin = window.open("","","toolbar=0,status=0,menubar=0,scrollbars=1,resizeable=1,width=400,height=420")
	hiWin = hiScoreWin.document


	hiWin.write("<html><head><title>Magnetron '99: Personal Hi Scores</title></head>")
	hiWin.write("<body background='Aura.gif' bgcolor='#000060' text='#ffffff'><center>")


	if ( BestScore.length==0 )
		hiWin.write("<font size=6>You Have Not Made Any Hiscores</font>")
	else
	{
		hiWin.write("<table width=350 border=2>")

		hiWin.write("<tr>")
		hiWin.write("<td colspan=40 align=center><font size=5 color='#ffa500'><b><font size=6>S</font>CORE</b></font></td>")
		hiWin.write("<td colspan=60 align=center><font size=5 color='#ffa500'><b><font size=6>D</font>ATE</b></font></td>")
		hiWin.write("</tr>")

		for (h=0; h<BestScore.length; h++)
		{
			hiWin.write("<tr>")

			hiWin.write("<td colspan=40 align=center><font size=4><b><code>"+num_text(BestScore[h].score, 9, '0')+"</code></b></font></td>")
			hiWin.write("<td colspan=60 align=center><font size=4>"+dayName[BestScore[h].day]+" "+BestScore[h].date+" "+monthName[BestScore[h].month]+" "+BestScore[h].year+"</font></td>")

			hiWin.write("</tr>")
		}

		hiWin.write("</table>")
	}

	hiWin.write("<br><br><center><form name='bot'><input type='button' name='closeme' value=' CLOSE WINDOW ' onClick='window.close()'></form>")

	hiWin.write("</center></body></html>")


	hiWin.close()
}






//*****************************************************
//		Management of Floating Documents
//*****************************************************


var PitXPos = 171;
var PitYPos = 110;

var DynDocs = new Object();

DynDocs.loading = new FloatingDocument( PitXPos, PitYPos + 188, "<table width=422><td align=center><font size=7 color='#dcf8ff'>Loading Images</font></td></table>", true );
DynDocs.clickhere = new FloatingDocument( PitXPos, PitYPos + 58, "<table width=422><td align=center><font size=6 color='#87cdfa'>Click Here</font></td></table>", false );
DynDocs.play = new FloatingDocument( PitXPos, PitYPos + 108, "<table width=422><td align=center><font size=5 color='#ffe4e1'>Press 'P' to play</font></td></table>", false );
DynDocs.demo = new FloatingDocument( PitXPos, PitYPos + 108, "<table width=422><td align=center><font size=5 color='#ffdab9'>Press 'D' for demo</font></td></table>", false );
DynDocs.scores = new FloatingDocument( PitXPos, PitYPos + 108, "<table width=422><td align=center><font size=5 color='#d2b48c'>Press 'H' for hi-scores</font></td></table>", false );
DynDocs.levelnum = new FloatingDocument( PitXPos, PitYPos + 88, false );
DynDocs.ready = new FloatingDocument( PitXPos, PitYPos + 88, "<table width=422><td align=center><font size=6 color='#ff4500'>Ready</font></td></table>", false );
DynDocs.set = new FloatingDocument( PitXPos, PitYPos + 88, "<table width=422><td align=center><font size=6 color='#ffa500'>Set</font></td></table>", false );
DynDocs.go = new FloatingDocument( PitXPos, PitYPos + 88, "<table width=422><td align=center><font size=7 color='#98fb98'>GO!</font></td></table>", false );
DynDocs.completed = new Array();
DynDocs.completed[0] = new FloatingDocument( "<font size=7 color='#a0eea0' style='font-weight=bold'>C</font>", false );
DynDocs.completed[1] = new FloatingDocument( "<font size=7 color='#90fb90' style='font-weight=bold'>O</font>", false );
DynDocs.completed[2] = new FloatingDocument( "<font size=7 color='#80ff80' style='font-weight=bold'>M</font>", false );
DynDocs.completed[3] = new FloatingDocument( "<font size=7 color='#60ff60' style='font-weight=bold'>P</font>", false );
DynDocs.completed[4] = new FloatingDocument( "<font size=7 color='#00fc00' style='font-weight=bold'>L</font>", false );
DynDocs.completed[5] = new FloatingDocument( "<font size=7 color='#60ff60' style='font-weight=bold'>E</font>", false );
DynDocs.completed[6] = new FloatingDocument( "<font size=7 color='#80ff80' style='font-weight=bold'>T</font>", false );
DynDocs.completed[7] = new FloatingDocument( "<font size=7 color='#90fb90' style='font-weight=bold'>E</font>", false );
DynDocs.completed[8] = new FloatingDocument( "<font size=7 color='#a0eea0' style='font-weight=bold'>D</font>", false );
DynDocs.compbonus = new FloatingDocument( PitXPos, PitYPos + 188, "<table width=422><td align=center><font size=5 color='#d8bfd8'>Level Completion Bonus</font></td></table>", false );
DynDocs.timebonus = new FloatingDocument( PitXPos, PitYPos + 188, "<table width=422><td align=center><font size=5 color='#d8bfd8'>Time Bonus Awarded</font></td></table>", false );
DynDocs.movebonus = new FloatingDocument( PitXPos, PitYPos + 188, "<table width=422><td align=center><font size=5 color='#d8bfd8'>Low Move Count Bonus</font></td></table>", false );
DynDocs.gameover = new Array();
DynDocs.gameover[0] = new FloatingDocument( "<font size=7 color='#ff4520' style='font-weight=bold'>G</font>", false );
DynDocs.gameover[1] = new FloatingDocument( "<font size=7 color='#ff6513' style='font-weight=bold'>A</font>", false );
DynDocs.gameover[2] = new FloatingDocument( "<font size=7 color='#ff850a' style='font-weight=bold'>M</font>", false );
DynDocs.gameover[3] = new FloatingDocument( "<font size=7 color='#ffa500' style='font-weight=bold'>E</font>", false );
DynDocs.gameover[4] = new FloatingDocument( "<font size=7 color='#ffa500' style='font-weight=bold'>O</font>", false );
DynDocs.gameover[5] = new FloatingDocument( "<font size=7 color='#ff850a' style='font-weight=bold'>V</font>", false );
DynDocs.gameover[6] = new FloatingDocument( "<font size=7 color='#ff6513' style='font-weight=bold'>E</font>", false );
DynDocs.gameover[7] = new FloatingDocument( "<font size=7 color='#ff4520' style='font-weight=bold'>R</font>", false );
DynDocs.newhiscore = new FloatingDocument( PitXPos, PitYPos + 98, "<table width=422><td align=center><font size=6 color='#eee8aa' style='font-weight=bold'>New Personal Hi-Score</font></td></table>", false );
DynDocs.demoalert = new FloatingDocument( PitXPos, PitYPos + 168, "<table width=422><td align=center><font size=7 color='#ffd0c0' style='font-weight=bold'>- DEMO -</font></td></table>", false );
DynDocs.demokey = new FloatingDocument( PitXPos, PitYPos + 218, "<table width=422><td align=center><font size=5 color='#c0d0ff' style='font-weight=bold'>Press any key</font></td></table>", false );
DynDocs.keychange = new FloatingDocument( PitXPos, PitYPos + 218, "<table width=422><td align=center><font size=5 color='gold' style='font-weight=bold'>Press new key for this action</font></td></table>", false );
DynDocs.keyalert = new FloatingDocument( PitXPos, PitYPos + 243, "<table width=422><td align=center><font size=5 color='gold' style='font-weight=bold'>That key is already being used</font></td></table>", false );
DynDocs.explosion = new Array();
DynDocs.explosion[0] = new FloatingDocument( "<img src='Explosion1.gif' width=80 height=80>", false );
DynDocs.explosion[1] = new FloatingDocument( "<img src='Explosion2.gif' width=80 height=80>", false );
DynDocs.explosion[2] = new FloatingDocument( "<img src='Explosion3.gif' width=80 height=80>", false );
DynDocs.explosion[3] = new FloatingDocument( "<img src='Explosion4.gif' width=80 height=80>", false );
DynDocs.explosion[4] = new FloatingDocument( "<img src='Explosion5.gif' width=80 height=80>", false );
DynDocs.explosion[5] = new FloatingDocument( "<img src='Explosion6.gif' width=80 height=80>", false );
DynDocs.explosion[6] = new FloatingDocument( "<img src='Explosion7.gif' width=80 height=80>", false );
DynDocs.explosion[7] = new FloatingDocument( "<img src='Explosion8.gif' width=80 height=80>", false );
DynDocs.explosion[8] = new FloatingDocument( "<img src='Explosion9.gif' width=80 height=80>", false );
DynDocs.explosion[9] = new FloatingDocument( "<img src='Explosion10.gif' width=80 height=80>", false );
DynDocs.pitExplosion = new Array();
DynDocs.pitExplosion[0] = new FloatingDocument( "<img src='PitExplosion1.gif' width=90 height=90>", false );
DynDocs.pitExplosion[1] = new FloatingDocument( "<img src='PitExplosion2.gif' width=90 height=90>", false );
DynDocs.pitExplosion[2] = new FloatingDocument( "<img src='PitExplosion3.gif' width=90 height=90>", false );
DynDocs.pitExplosion[3] = new FloatingDocument( "<img src='PitExplosion4.gif' width=90 height=90>", false );
DynDocs.pitExplosion[4] = new FloatingDocument( "<img src='PitExplosion5.gif' width=90 height=90>", false );
DynDocs.pitExplosion[5] = new FloatingDocument( "<img src='PitExplosion6.gif' width=90 height=90>", false );
DynDocs.pitExplosion[6] = new FloatingDocument( "<img src='PitExplosion7.gif' width=90 height=90>", false );
DynDocs.pitExplosion[7] = new FloatingDocument( "<img src='PitExplosion8.gif' width=90 height=90>", false );
DynDocs.pitExplosion[8] = new FloatingDocument( "<img src='PitExplosion9.gif' width=90 height=90>", false );
DynDocs.pitExplosion[9] = new FloatingDocument( "<img src='PitExplosion10.gif' width=90 height=90>", false );
DynDocs.sequence = new FloatingDocument( PitXPos - 120, PitYPos + 30, "<font size=4 color='darkgoldenrod'>Sequence:</font>", false );
DynDocs.newDiff = new FloatingDocument( PitXPos, PitYPos + 135, "<table width=422><td align=center><font size=4 color='#ffffff'>New Difficulty Setting Available</font></td></table>", false );

function position_floating_docs()
//	Not used at present, docs are positioned when they are created.
//	Retained for future use if there is a way to determine the Pit position, we can reposition
//	the docs should the user re-size their browser window.
{
	DynDocs.clickhere.move_to( PitXPos + 146, PitYPos + 58 );
	DynDocs.play.move_to( PitXPos + 138, PitYPos + 108 );
	DynDocs.demo.move_to( PitXPos + 126, PitYPos + 108 );
	DynDocs.scores.move_to( PitXPos + 109, PitYPos + 108 );
	DynDocs.ready.move_to( PitXPos + 171, PitYPos + 88 );
	DynDocs.set.move_to( PitXPos + 191, PitYPos + 88 );
	DynDocs.go.move_to( PitXPos + 171, PitYPos + 88 );
	DynDocs.compbonus.move_to( PitXPos + 83, PitYPos + 188 );
	DynDocs.timebonus.move_to( PitXPos + 100, PitYPos + 188 );
	DynDocs.movebonus.move_to( PitXPos + 86, PitYPos + 188 );
	DynDocs.newhiscore.move_to( PitXPos + 118, PitYPos + 98 );
	DynDocs.demoalert.move_to( PitXPos + 111, PitYPos + 168 );
	DynDocs.demokey.move_to( PitXPos + 143, PitYPos + 218 );
	DynDocs.keychange.move_to( PitXPos + 64, PitYPos + 218 );
	DynDocs.keyalert.move_to( PitXPos + 54, PitYPos + 243 );
	DynDocs.sequence.move_to( PitXPos - 120, PitYPos + 30 );
	DynDocs.newDiff.move_to( PitXPos + 94, PitYPos + 135 );
}
