/*
  Lost In Maze! Part 2 - Robby vs The B9-Robots
  (c) Norbert Landsteiner 2009; www.masswerk.at
  (based on "JavaScript-PacMan 3D" (c) 1996-2007 N. Landsteiner)
  
  fixed opacity effects for MSIE 03/2009
*/

// preload & setup

var elements = new Object();

var pacimages = [
	'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'k', 'l', 'm', 'n',
	'o', 'p', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'pnt',
	'rb1', 'rb2', 'rb3', 'rf1', 'rf2', 'rf3', 'rl1', 'rl2', 'rl3', 'rr1', 'rr2', 'rr3',
	'rx0', 'rx1', 'rx2', 'rx3', 'rx4', 'bx', 'ax',
	'rbf', 'rbl', 'rbr', 'rbb',
	's0', 'sf', 'sl', 'sr', 'sb',
	'b1f', 'b1r', 'b1l', 'b1b',
	'b2f', 'b2r', 'b2l', 'b2b',
	'b3f', 'b3r', 'b3l', 'b3b',
	'b4f', 'b4r', 'b4l', 'b4b',
	'baf', 'bar', 'bal', 'bab',
	'bnf', 'bnr', 'bnl', 'bnb',
	'af1', 'af2', 'af3', 'al1', 'al2', 'al3',
	'ar1', 'ar2', 'ar3', 'ab1', 'ab2', 'ab3',
	'blast1', 'blast2', 'blast3', 'blast4', 'blast5',
	'bonus0', 'bonus1', 'bonus2', 'bonus3', 'bonus4',
	'gameover', 'gamepaused'
];
var pacimages2 = [
	'life', 'shell', 'xx', 'newgame_lo', 'newgame_hi', 'newgame_dn',
	'neon_lo', 'neon_hi'
];

var imgRef, imgCnt, imgTotal;
var imgPath='lostinmaze2images/';
var sprites;
var mspacImgsLoaded=false;

function init() {
	elements.maze=getElement('maze');
	if ((!elements.maze) || (!document.images) || (!document.createElement)) {
		if (prompt('Sorry, DOM compatible browser (Mozilla, Firefox, Internet Explorer 5+, Safari, etc) required.\n\nTry the legacy version for older browsers?\n')) {
			self.location.replace('legacy/JS-PacManPlus.htm');
		}
		return;
	}
	setVisibility(getElement('progress'), true);
	elements.scoredisplay=getElement('scoredisplay');
	elements.leveldisplay=getElement('leveldisplay');
	elements.mazedisplay=getElement('mazedisplay');
	preload();
}

function preload() {
	var i;
	imgRef=new Object();
	imgCnt=0;
	imgTotal=pacimages.length+pacimages2.length;
	for (i=0; i<pacimages.length; i++) {
		var n=pacimages[i];
		var img=imgRef[n]=new Image();
		img.src=imgPath+n+'.png';
		if (img.complete) {
			imgTotal--;
		}
		else {
			img.onload=preloadHandler;
		}
	}
	for (i=0; i<pacimages2.length; i++) {
		var n=pacimages2[i];
		var img=imgRef[n]=new Image();
		img.src=imgPath+n+'.gif';
		if (img.complete) {
			imgTotal--;
		}
		else {
			img.onload=preloadHandler;
		}
	}
	if (imgTotal==0) preloadComplete();
}

function preloadHandler() {
	imgCnt++;
	var d=getElement('progressbar');
	var v = imgCnt/imgTotal;
	d.style.width=Math.round(160*v)+'px';
	d=getElement('progressvalue');
	d.innerHTML=Math.round(v*100)+'%';
	if (imgCnt==imgTotal) setTimeout('preloadComplete()', 10);
}

function preloadComplete() {
	var d=getElement('progress');
	setVisibility(d, false);
	d.style.display='none';
	initMaze();
	initSprites();
	setVisibility(getElement('controls'), true);
	var select=getElement('mazeselect');
	select.selectedIndex=0;
	setQuality(settingsQualityValue);
	setSpeed(settingsSpeedValue);
	enableKeyboard();
	if (window.activateTouchControls) activateTouchControls();
	setTimeout('newGame()', 10);
}

function initMaze() {
	var r,c, imgsrc, i, id, x, y, z, mpr;
	var maze = elements.maze=document.getElementById('maze');
	var misieFilter="progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+imgPath+"x.png', sizingMethod='crop')";
	for (r=0; r<22; r++) {
		mpr = mazePos[r+1] = new Array();
		for (c=0; c<19; c++) {
			x= 10+(21-r)*14+c*24;
			y= 20+r*11+c*6;
			z= 1+c*7+r*133;
			mpr[c+1]= {x: x-6, y: y-17, z:z+1};
			id='t'+(r+1)+'_'+(c+1);
			i=document.createElement('img');
			i.id=id;
			if (msieLe6) {
				i.src=imgPath+'xx.gif';
				i.style.filter=misieFilter;
			}
			else {
				i.src=imgPath+'x.png';
			}
			i.width=28; i.height=17;
			i.style.display='block';
			i.style.position='absolute';
			i.style.left=x+'px';
			i.style.top=y+'px';
			i.style.zIndex=z;
			maze.appendChild(i);
			elements[id]=i;
		}
	}
}

function initSprites() {
	var img, id, d, gd, i;
	var maze=elements.maze;
	var xpng=imgPath+'x.png';
	var xgif= imgPath+'xx.gif';
	if (msie) {
		var misieFilter="progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+xpng+"', sizingMethod='crop')";
		var ximg=(msieLe6)? xgif:xpng;
		for (i=1; i<=4; i++) {
			id='g'+i;
			d = elements[id]=document.createElement('div');
			d.style.visibilty='hidden';
			d.style.position='absolute';
			
			id='gb'+i;
			gd = elements[id]=document.createElement('div');
			gd.style.visibilty='hidden';
			gd.style.position='absolute';
			gd.style.zIndex=1;
			id='gbi'+i;
			img=elements[id]=document.createElement('img');
			img.id=id;
			img.src=ximg;
			img.width=38; img.height=57;
			if (msieLe6) img.style.filter=misieFilter;
			gd.appendChild(img);
			d.appendChild(gd);
			
			id='ga'+i;
			gd = elements[id]=document.createElement('div');
			gd.style.visibilty='hidden';
			gd.style.position='absolute';
			gd.style.zIndex=2;
			id='gai'+i;
			img=elements[id]=document.createElement('img');
			img.id=id;
			img.src=ximg;
			img.width=38; img.height=57;
			if (msieLe6) img.style.filter=misieFilter;
			gd.appendChild(img);
			d.appendChild(gd);
			maze.appendChild(d);
			
			id='bonus'+i;
			gd = elements[id]=document.createElement('div');
			gd.style.visibilty='hidden';
			gd.style.position='absolute';
			id='ibonus'+i;
			img=elements[id]=document.createElement('img');
			img.id=id;
			img.src=ximg;
			img.width=29; img.height=10;
			if (msieLe6) img.style.filter=misieFilter;
			gd.appendChild(img);
			maze.appendChild(gd);
		}
		d = elements.pac=document.createElement('div');
		d.id='pac';
		d.style.visibilty='hidden';
		d.style.position='absolute';
		
		img = elements.ipac=document.createElement('img');
		img.id='ipac';
		img.src=ximg;
		img.width=45; img.height=57;
		if (msieLe6) img.style.filter=misieFilter;
		img.style.position='absolute';
		img.style.display='block';
		img.style.zIndex=1;
		d.appendChild(img);
		
		img = elements.blaster=document.createElement('img');
		img.id='blaster';
		img.src=ximg;
		img.width=45; img.height=57;
		if (msieLe6) img.style.filter=misieFilter;
		img.style.position='absolute';
		img.style.display='block';
		img.style.visibilty='hidden';
		img.style.zIndex=2;
		d.appendChild(img);
		maze.appendChild(d);
		
		d = elements.asset=document.createElement('div');
		d.id='asset';
		d.style.visibilty='hidden';
		d.style.position='absolute';
		img = elements.iasset=document.createElement('img');
		img.id='iasset';
		img.src=ximg;
		img.width=13; img.height=23;
		if (msieLe6) img.style.filter=misieFilter;
		d.appendChild(img);
		maze.appendChild(d);
		
		img = elements.shot=document.createElement('img');
		img.id='shot';
		img.style.visibilty='hidden';
		img.style.position='absolute';
		img.src=ximg;
		img.width=45; img.height=57;
		if (msieLe6) img.style.filter=misieFilter;
		maze.appendChild(img);
		
		img = elements.blast=document.createElement('img');
		img.id='blast';
		img.style.visibilty='hidden';
		img.style.position='absolute';
		img.src=ximg;
		img.width=86; img.height=25;
		if (msieLe6) img.style.filter=misieFilter;
		maze.appendChild(img);
		
		sprites = {
			pac: {'div': elements.pac, 'img': elements.ipac, 'blaster': elements.blaster},
			g: {
				'1': { 'div': elements.g1, 'b': elements.gb1, 'bi': elements.gbi1, 'a': elements.ga1, 'ai': elements.gai1 },
				'2': { 'div': elements.g2, 'b': elements.gb2, 'bi': elements.gbi2, 'a': elements.ga2, 'ai': elements.gai2 },
				'3': { 'div': elements.g3, 'b': elements.gb3, 'bi': elements.gbi3, 'a': elements.ga3, 'ai': elements.gai3 },
				'4': { 'div': elements.g4, 'b': elements.gb4, 'bi': elements.gbi4, 'a': elements.ga4, 'ai': elements.gai4 }
			},
			bonus: {
				'1': {'div': elements.bonus1, 'img': elements.ibonus1},
				'2': {'div': elements.bonus2, 'img': elements.ibonus2},
				'3': {'div': elements.bonus3, 'img': elements.ibonus3},
				'4': {'div': elements.bonus4, 'img': elements.ibonus4}
			},
			asset: {'div': elements.asset, 'img': elements.iasset },
			shot: elements.shot,
			blast: elements.blast
		};
	}
	else {
		for (var i=1; i<=4; i++) {
			id='g'+i;
			d = elements[id]=document.createElement('div');
			d.id=id;
			d.style.visibilty='hidden';
			d.style.position='absolute';
			
			id='gb'+i;
			img=elements[id]=document.createElement('img');
			img.id=id;
			img.src=xpng;
			img.width=38; img.height=57;
			img.style.position='absolute';
			img.style.display='block';
			img.style.zIndex=1;
			d.appendChild(img);
			
			id='ga'+i
			img=elements[id]=document.createElement('img');
			img.id=id;
			img.src=xpng;
			img.width=38; img.height=57;
			img.style.position='absolute';
			img.style.display='block';
			img.style.zIndex=2;
			d.appendChild(img);
			maze.appendChild(d);
			
			id='bonus'+i;
			img=elements[id]=document.createElement('img');
			img.id=id;
			img.src=xpng;
			img.width=29; img.height=10;
			img.style.visibilty='hidden';
			img.style.position='absolute';
			img.style.display='block';
			maze.appendChild(img);
		}
		d = elements.pac=document.createElement('div');
		d.id='pac';
		d.style.visibilty='hidden';
		d.style.position='absolute';
		
		img = elements.ipac=document.createElement('img');
		img.id='ipac';
		img.src=xpng;
		img.width=45; img.height=57;
		img.style.position='absolute';
		img.style.display='block';
		img.style.zIndex=1;
		d.appendChild(img);
		
		img = elements.blaster=document.createElement('img');
		img.id='blaster';
		img.src=xpng;
		img.width=45; img.height=57;
		img.style.position='absolute';
		img.style.display='block';
		img.style.zIndex=2;
		img.style.visibilty='hidden';
		d.appendChild(img);
		maze.appendChild(d);
		
		img = elements.asset=document.createElement('img');
		img.id='asset';
		img.src=xpng;
		img.width=13; img.height=23;
		img.style.visibilty='hidden';
		img.style.position='absolute';
		img.style.display='block';
		maze.appendChild(img);
		
		img = elements.shot=document.createElement('img');
		img.id='shot';
		img.src=xpng;
		img.width=45; img.height=57;
		img.style.visibilty='hidden';
		img.style.position='absolute';
		img.style.display='block';
		maze.appendChild(img);
		
		img = elements.blast=document.createElement('img');
		img.id='blast';
		img.src=xpng;
		img.width=86; img.height=25;
		img.style.visibilty='hidden';
		img.style.position='absolute';
		img.style.display='block';
		maze.appendChild(img);
		
		sprites = {
			pac: {'div': elements.pac, 'img': elements.ipac, 'blaster': elements.blaster},
			g: {
				'1': { 'div': elements.g1, 'b': elements.gb1, 'bi': elements.gb1, 'a': elements.ga1, 'ai': elements.ga1 },
				'2': { 'div': elements.g2, 'b': elements.gb2, 'bi': elements.gb2, 'a': elements.ga2, 'ai': elements.ga2 },
				'3': { 'div': elements.g3, 'b': elements.gb3, 'bi': elements.gb3, 'a': elements.ga3, 'ai': elements.ga3 },
				'4': { 'div': elements.g4, 'b': elements.gb4, 'bi': elements.gb4, 'a': elements.ga4, 'ai': elements.ga4 }
			},
			bonus: {
				'1': {'div': elements.bonus1, 'img': elements.bonus1},
				'2': {'div': elements.bonus2, 'img': elements.bonus2},
				'3': {'div': elements.bonus3, 'img': elements.bonus3},
				'4': {'div': elements.bonus4, 'img': elements.bonus4}
			},
			asset: {'div': elements.asset, 'img': elements.asset },
			shot: elements.shot,
			blast: elements.blast
		};
	}
	
	d=elements.gameover=getElement('gameover');
	setVisibility(d, false);
	if (msieLe6) {
		d.innerHTML='<img id="imggameover" src="'+xgif+'" width="216" height="38" alt="">';
		document.all.imggameover.style.filter="progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+imgPath+"gameover.png', sizingMethod='scale')";
	}
	else {
		d.innerHTML='<img src="'+imgPath+'gameover.png" width="216" height="38" alt="">';
	}
	d.style.left='279px';
	d.style.top='154px';
	d.style.zIndex=2998;
	d=elements.gamepaused=getElement('gamepaused');
	setVisibility(d, false);
	if (msieLe6) {
		d.innerHTML='<img id="imggamepaused" src="'+xgif+'" width="231" height="37" alt="">'; document.all.imggamepaused.style.filter="progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+imgPath+"gamepaused.png', sizingMethod='scale')";
	}
	else {
		d.innerHTML='<img src="'+imgPath+'gamepaused.png" width="231" height="37" alt="">';
	}
	d.style.left='271px';
	d.style.top='154px';
	d.style.zIndex=2999;
	if (msieLe6 && elements.g1 && elements.g1.filters /*&& elements.g1.filters.item(0)*/) {
		setSpriteImg=setSpriteImgMsieLe6;
		setMaze=setMazeMsieLe6;
	}
	elements.restartdialog=getElement('restartdialog');
	elements.dialogscreen=getElement('dialogscreen');
	elements.dialogscreenimg=getElement('dialogscreenimg');
	setSpriteImg(sprites.asset.img, 's0');
}

// definitions

var settingsQuality=new Array(5, 6, 7);
var settingsSpeed=new Array(258, 235, 212, 190);
var settingsQualityValue=1;
var settingsSpeedValue=1;
var aStep=6;
var aSpeed=252;
var gameDelay;

var blinkRate=4;
var blinkSteps=7;
var pillFactor=1.75;
var pillMaxLength=26;
var pillDecrement=5;
var eyesFactor=.75;
var shellFactor=.5;
var assetProbability1=0.005;
var assetProbability2=0.001;
var bonusLifeScore=10000;
var useInstantTurns=true;
var allwaysStartInScatterMode=false;
var pillMinLength, bonusLength;
var ghomeOfs=16;
var dotsound;

if (typeof window.useSound == 'undefined') useSound=false;

var ghostResetDelay=20;
var ghostResetAlpha=.8;
var ghostResetDelta=.05;

var mazeMode ='Sequentially';

var highscore=0;

var f1= new Array();
var f2= new Array();
var fw= new Array();
var fft= new Array();
var fgh= new Array();
for (var i=1; i<=22; i++) {
	f1[i]=new Array();
	f2[i]=new Array();
	fw[i]=new Array();
	fft[i]=new Array();
}

var b9Levels = [
{
name: "West of Mars",
maze: [
	'ahhhhhhihhhihhhhhhc',
	'v......o...o......v',
	'v.n.ac...n...ac.n.v',
	'vpo.bd.lhfhm.bd.opv',
	'v.................v',
	'v.lm.ahm.n.lhc.lm.v',
	'v....v...v...v....v',
	'bhhc.oxlhfhmxo.ahhd',
	'xxxv.xxxxxxxxx.vxxx',
	'hhhd.nxautwcxn.bhhh',
	'xxxx.vxvxxxvxv.xxxx',
	'hhhc.oxbhhhdxo.ahhh',
	'xxxv.xxxxxxxxx.vxxx',
	'ahhd.nxlhihmxn.bhhc',
	'v....v...v...v....v',
	'v.ac.bhm.o.lhd.ac.v',
	'vpvv.....x.....vvpv',
	'v.bd.ahm.n.lhc.bd.v',
	'v....v...v...v....v',
	'v.lm.o.lhfhm.o.lm.v',
	'v.................v',
	'bhhhhhhhhhhhhhhhhhd'
]
},
{
name: "The Saturnian Base",
maze: [
	'ahhhhhhhcxahhhhhhhc',
	'v.......vxv.......v',
	'v.n.ahc.vxv.ahc.n.v',
	'vpv.bhd.oxo.bhd.vpv',
	'v.v.............v.v',
	'v.bm.n.lhihm.n.ld.v',
	'v....v...v...v....v',
	'bhhc.bhmxoxlhd.ahhd',
	'xxxv.xxxxxxxxx.vxxx',
	'lhhd.nxautwcxn.bhhm',
	'xxxx.vxvxxxvxv.xxxx',
	'lhhc.oxbhhhdxo.ahhm',
	'xxxv.xxxxxxxxx.vxxx',
	'ahhd.ahmxnxlhc.bhhc',
	'v....v...v...v....v',
	'v.am.o.lhfhm.o.lc.v',
	'vpv......x......vpv',
	'v.o.n.lhcxahm.n.o.v',
	'v...v...vxv...v...v',
	'v.lhfhm.oxo.lhfhm.v',
	'v........x........v',
	'bhhhhhhhmxlhhhhhhhd'
]
},
{
name: "The Krell Library",
maze: [
	'ahhhhhhhhihhhhhhhhc',
	'v........o........v',
	'vpac.ahc...ahc.acpv',
	'v.bd.bhd.n.bhd.bd.v',
	'v........v........v',
	'bhhc.n.lhyhm.n.ahhd',
	'xxxv.v...v...v.vxxx',
	'xahd.ehmxoxlhg.bhcx',
	'xv...vxxxxxxxv...vx',
	'ld.n.oxautwcxo.n.bm',
	'xx.v.xxvxxxvxx.v.xx',
	'lc.o.nxbhhhdxn.o.am',
	'xv...vxxxxxxxv...vx',
	'xbhc.ehmxnxlhg.ahdx',
	'xxxv.v...v...v.vxxx',
	'ahhd.o.lhfhm.o.bhhc',
	'v........x........v',
	'v.n.lihm.n.lhim.n.v',
	'vpv..v...v...v..vpv',
	'v.bm.o.lhfhm.o.ld.v',
	'v.................v',
	'bhhhhhhhhhhhhhhhhhd'
]
},
{
name: "Launch Pad 7",
maze: [
	'ahhhhhhhcxahhhhhhhc',
	'v.......vxv.......v',
	'vpahc.n.vxv.n.ahcpv',
	'v.bhd.v.oxo.v.bhd.v',
	'v.....v.....v.....v',
	'v.lim.o.nxn.o.lim.v',
	'v..v....vxv....v..v',
	'bc.o.nxldxbmxn.o.ad',
	'xv...vxxxxxxxv...vx',
	'ld.lhdxautwcxbhm.bm',
	'xx.xxxxvxxxvxxxx.xx',
	'lc.lhcxbhhhdxahm.am',
	'xv...vxxxxxxxv...vx',
	'ad.n.oxlcxamxo.n.bc',
	'v..v....vxv....v..v',
	'v.lfm.n.oxo.n.lfm.v',
	'v.....v..x..v.....v',
	'v.ahc.v.lhm.v.ahc.v',
	'vpehg.v.....v.ehgpv',
	'v.bhd.o.nxn.o.bhd.v',
	'v.......vxv.......v',
	'bhhhhhhhdxbhhhhhhhd'
]
},
{
name: "The Tellurian Gardens",
maze: [
	'ahhhhcxahhhcxahhhhc',
	'v....oxv...vxo....v',
	'v.ac.xxv.n.vxx.ac.v',
	'vpbd.nxo.o.oxn.bdpv',
	'v....v.......v....v',
	'v.lhhd.lhihm.bhhm.v',
	'v........v........v',
	'bhhc.ahmxoxlhc.ahhd',
	'xxxv.vxxxxxxxv.vxxx',
	'lhhd.oxautwcxo.bhhm',
	'xxxx.xxvxxxvxx.xxxx',
	'lhhc.nxbhhhdxn.ahhm',
	'xxxv.vxxxxxxxv.vxxx',
	'ahhd.bhmxnxlhd.bhhc',
	'v........v........v',
	'v.lhhc.lhfhm.ahhm.v',
	'v....v...x...v....v',
	'v.ac.o.lhihm.o.ac.v',
	'vpvv.....v.....vvpv',
	'v.bd.nxn.o.nxn.bd.v',
	'v....vxv...vxv....v',
	'bhhhhdxbhhhdxbhhhhd'
]
}
];

var pacLevels = [
{
name: "Remember Pac-Man?",
maze: [
	'ahhhhhhhhihhhhhhhhc',
	'v........v........v',
	'vpac.ahc.v.ahc.acpv',
	'v.bd.bhd.o.bhd.bd.v',
	'v.................v',
	'v.lm.n.lhihm.n.lm.v',
	'v....v...v...v....v',
	'bhhc.ehmxoxlhg.ahhd',
	'xxxv.vxxxxxxxv.vxxx',
	'lhhd.oxautwcxo.bhhm',
	'xxxx.xxvxxxvxx.xxxx',
	'lhhc.nxbhhhdxn.ahhm',
	'xxxv.vxxxxxxxv.vxxx',
	'ahhd.oxlhihmxo.bhhc',
	'v........v........v',
	'v.lc.lhm.o.lhm.am.v',
	'vp.v.....x.....v.pv',
	'em.o.n.lhihm.n.o.lg',
	'v....v...v...v....v',
	'v.lhhfhm.o.lhfhhm.v',
	'v.................v',
	'bhhhhhhhhhhhhhhhhhd'
]
},
{
name: "Remember Ms Pac-Man &ndash; Part 1",
maze: [
	'ahhhhihhhhhhhihhhhc',
	'v....v.......v....v',
	'vplm.o.lhhhm.o.lmpv',
	'v.................v',
	'bc.n.ahc.n.ahc.n.ad',
	'ld.v.bhd.v.bhd.v.bm',
	'xx.v.....v.....v.xx',
	'lc.bhmxlhfhmxlhd.am',
	'xv.xxxxxxxxxxxxx.vx',
	'xv.ahmxautwcxlhc.vx',
	'xv.vxxxvxxxvxxxv.vx',
	'ld.oxnxbhhhdxnxo.bm',
	'xx.xxvxxxxxxxvxx.xx',
	'lc.lhfhmxnxlhfhm.am',
	'xv.....xxvxx.....vx',
	'ad.lhm.lhfhm.lhm.bc',
	'v........x........v',
	'v.ac.ahm.n.lhc.ac.v',
	'vpvv.v...v...v.vvpv',
	'v.bd.o.lhfhm.o.bd.v',
	'v.................v',
	'bhhhhhhhhhhhhhhhhhd'
]
},
{
name: "Remember Ms Pac-Man &ndash; Part 2",
maze: [
	'lhhhhihhhhhhhihhhhm',
	'xxxxxv.......vxxxxx',
	'ahhmxo.lhihm.oxlhhc',
	'vp.......v.......pv',
	'v.ahhm.n.v.n.lhhc.v',
	'v.v....v.o.v....v.v',
	'v.o.lcxv...vxam.o.v',
	'v....vxbhhhdxv....v',
	'ehhm.vxxxxxxxv.lhhg',
	'v....oxautwcxo....v',
	'v.lc.xxvxxxvxx.am.v',
	'v..v.nxbhhhdxn.v..v',
	'bc.v.vxxxxxxxv.v.ad',
	'xv.o.bmxahcxld.o.vx',
	'xv......vxv......vx',
	'ld.lhim.bhd.lihm.bm',
	'xx...v..xxx..v...xx',
	'am.n.o.lhihm.o.n.lc',
	'vp.v.....v.....v.pv',
	'v.ld.lhm.o.lhm.bm.v',
	'v.................v',
	'bhhhhhhhhhhhhhhhhhd'
]
},
{
name: "Remember Ms Pac-Man &ndash; Part 3",
maze: [
	'ahhhhhhihhhihhhhhhc',
	'v......v...v......v',
	'vpahhm.o.n.o.lhhcpv',
	'v.o......v......o.v',
	'v...n.ac.v.ac.n...v',
	'bhm.v.bd.o.bd.v.lhd',
	'x...v.........v...x',
	'n.nxbmxlhhhmxldxn.n',
	'v.vxxxxxxxxxxxxxv.v',
	'v.bmxnxautwcxnxld.v',
	'v.xxxvxvxxxvxvxxx.v',
	'v.nxldxbhhhdxbmxn.v',
	'v.vxxxxxxxxxxxxxv.v',
	'v.bmxahmxnxlhcxld.v',
	'v....v...v...v....v',
	'em.n.o.lhfhm.o.n.lg',
	'vp.v.....x.....v.pv',
	'v.ld.ahm.n.lhc.bm.v',
	'v....v...v...v....v',
	'v.lm.v.lhfhm.v.lm.v',
	'v....v.......v....v',
	'bhhhhfhhhhhhhfhhhhd'
]
},
{
name: "Remember Ms Pac-Man &ndash; Part 4",
scatterPos: [[0,0], [3,4], [17,20], [3,20], [17,4]],
maze: [
	'ahhhhhhhhhhhhhhhhhc',
	'v.................v',
	'v.n.ac.ahhhc.ac.n.v',
	'vpv.bd.v...v.bd.vpv',
	'v.v....v.n.v....v.v',
	'v.bm.n.o.v.o.n.ld.v',
	'v....v...v...v....v',
	'bc.lhyhmxoxlhyhm.ad',
	'ld...vxxxxxxxv...bm',
	'xxxn.oxautwcxo.nxxx',
	'lhhg.xxvxxxvxx.ehhm',
	'xxxo.nxbhhhdxn.oxxx',
	'lc...vxxxxxxxv...am',
	'xv.n.bhmxnxlhd.n.vx',
	'xv.v...xxvxx...v.vx',
	'ad.bhm.nxoxn.lhd.bc',
	'v......vxxxv......v',
	'v.am.n.bhhhd.n.lc.v',
	'vpv..v.......v..vpv',
	'v.o.lfhm.n.lhfm.o.v',
	'v........v........v',
	'bhhhhhhhhfhhhhhhhhd'
]
}
];

var spaceLevels = [
{
name: "The Outskirts of Saturn",
maze: [
	'ahhhhhihhhhhihhhhhc',
	'v.....o.....o.....v',
	'v.ahc...ahc...ahc.v',
	'vpvxv.n.bhd.n.vxvpv',
	'v.vxv.v.....v.vxv.v',
	'v.bhd.bm.n.ld.bhd.v',
	'v........v........v',
	'bhhc.amxlfmxlc.ahhd',
	'xxxv.vxxxxxxxv.vxxx',
	'lhhd.oxautwcxo.bhhm',
	'xxxx.xxvxxxvxx.xxxx',
	'lhhc.nxbhhhdxn.ahhm',
	'xxxv.vxxxxxxxv.vxxx',
	'xxxv.bmxlimxld.vxxx',
	'xxxv.....v.....vxxx',
	'ahhd.ahm.o.lhc.bhhc',
	'v....v...x...v....v',
	'v.am.o.lhihm.o.lc.v',
	'vpv......v......vpv',
	'v.o.lhhm.o.lhhm.o.v',
	'v.................v',
	'bhhhhhhhhhhhhhhhhhd'
]
},
{
name: "Space Station One",
maze: [
	'ahhhcahhhhhhhcahhhc',
	'v...vv.......vv...v',
	'v.n.vv.ahhhc.vv.n.v',
	'v.o.bd.bhhhd.bd.o.v',
	'v.................v',
	'v.lm.ahm.n.lhc.lm.v',
	'vp...v...v...v...pv',
	'bhhc.oxlhfhmxo.ahhd',
	'xxxv.xxxxxxxxx.vxxx',
	'lhhd.nxautwcxn.bhhm',
	'xxxx.vxvxxxvxv.xxxx',
	'lhhc.oxbhhhdxo.ahhm',
	'xxxv.xxxxxxxxx.vxxx',
	'ahhd.nxlhihmxn.bhhc',
	'v....vxxxvxxxv....v',
	'v.am.bhmxoxlhd.lc.v',
	'vpv....xxxxx....vpv',
	'v.o.lm.lhihm.lm.o.v',
	'v........v........v',
	'v.z.ac.z.o.z.ac.z.v',
	'v...vv.......vv...v',
	'bhhhdbhhhhhhhdbhhhd'
]
},
{
name: "The Martian Palace",
maze: [
	'ahhhhhhcxxxahhhhhhc',
	'v......vxxxv......v',
	'v.ac.n.bhhhd.n.ac.v',
	'opbd.o.xxxxx.o.bdpo',
	'x......ahhhc......x',
	'n.lhhm.vlhmv.lhhm.n',
	'v......vlhmv......v',
	'bc.ahc.bhhhd.ahc.ad',
	'xv.vxv.xxxxx.vxv.vx',
	'xv.bhd.autwc.bhd.vx',
	'xv.....vxxxv.....vx',
	'xv.ahc.bhhhd.ahc.vx',
	'xv.vxv.xxxxx.vxv.vx',
	'ad.bhd.ahhhc.bhd.bc',
	'v......vxxxv......v',
	'o.lhhc.bhhhd.ahhm.o',
	'x....v.xxxxx.v....x',
	'n.am.o.ahhhc.o.lc.n',
	'vpv....vahcv....vpv',
	'v.o.lm.vvkvv.lm.o.v',
	'v......vbhdv......v',
	'bhhhhhhdxxxbhhhhhhd'
]
},
{
name: "Alien Power Station",
maze: [
	'ahhhhcxahhhcxahhhhc',
	'v....vxv...vxv....v',
	'v.ac.oxo.z.oxo.ac.v',
	'vpbd...........bdpv',
	'v....nxn.n.nxn....v',
	'v.n.lgxv.v.vxem.n.v',
	'v.v..oxoxoxoxo..v.v',
	'v.bm..xxxxxxx..ld.v',
	'v....nxxxxxxxn....v',
	'bmxlhdxautwcxbhmxld',
	'xxxxxxxvxxxvxxxxxxx',
	'amxlhcxbhhhdxahmxlc',
	'v....vxxxxxxxv....v',
	'v.am.oxlhihmxo.lc.v',
	'v.v......v......v.v',
	'v.o.lihm.o.lhim.o.v',
	'v....v...x...v....v',
	'v.ac.o.lhihm.o.ac.v',
	'vpvv.....v.....vvpv',
	'v.bd.nxn.o.nxn.bd.v',
	'v....vxv...vxv....v',
	'bhhhhdxbhhhdxbhhhhd'
]
},
{
name: "Star City",
maze: [
	'ahhhcxahhhhhcxahhhc',
	'o...oxo.....oxo...o',
	'x.z.....lim.....z.x',
	'np..nxn..v..nxn..pn',
	'bm.ldxbm.o.ldxbm.ld',
	'xx...............xx',
	'am.lc.ahcxahc.am.lc',
	'v...o.bhdxbhd.o...v',
	'v.n...xxxxxxx...n.v',
	'v.bhhmxautwcxlhhd.v',
	'v.xxxxxvxxxvxxxxx.v',
	'v.ahhmxbhhhdxlhhc.v',
	'v.o...xxxxxxx...o.v',
	'v...n.amxnxlc.n...v',
	'bm.ld.vxxvxxv.bm.ld',
	'xx.xx.vxlfmxv.xx.xx',
	'am.lc.v..x..v.am.lc',
	'vp..v.v.ahc.v.v..pv',
	'o.n.o.o.vxv.o.o.n.o',
	'x.o.....bhd.....o.x',
	'n...nxn.....nxn...n',
	'bhhhdxbhhhhhdxbhhhd'
]
}
];

var levels, allLevels;

var tx= new Array();
var ty= new Array();

var t1= new Array();
t1[0]=0;
t1[1]= 9; // rd
t1[2]=10; // ld
t1[3]= 5; // ru
t1[4]= 6; // lu
t1[5]=13; // rdu
t1[6]=14; // ldu
t1[7]=11; // rld
t1[8]= 7; // rlu
t1[9]=15; // rlud
tx[0]=0;  ty[0]=0;
tx[1]=1;  ty[1]=0;  //r
tx[2]=-1; ty[2]=0;  //l
tx[4]=0;  ty[4]=-1; //u
tx[8]=0;  ty[8]=1;  //d


var t2 = new Array();
t2[0]= [0];
t2[1]= [1];
t2[2]= [2];
t2[4]= [4];
t2[8]= [8];
t2[3]= [1, 2];
t2[9]= [1, 8];
t2[10]=[2, 8];
t2[12]=[4, 8];
t2[5]= [1, 4];
t2[6]= [2, 4];
t2[7]= [1, 2, 4];
t2[11]=[1, 2, 8];
t2[13]=[1, 4, 8];
t2[14]=[2, 4, 8];
t2[15]=[1, 2, 4, 8];

var tdx=[2, 0, 1];
var tdy=[4, 0, 8];

var t3 = new Array();
t3[0]=0; t3[1]=2; t3[2]=1; t3[4]=8; t3[8]=4;

var mazePos = new Array();

var nextNodes= new Array();
var pacNext=null;
var pacLast=null;

var gHomePos= new Array([11,10], [11,9], [11,11],  [10,10] );
var gbid= new Array(1,2,4,8);
var scatterPos=new Array( [0,0], [3,3], [17,20], [3,20], [17,3]);

var g= new Array();
for (var i=1; i<=4; i++) {
	g[i]=new Ghost();
	g[i].bid=gbid[i-1];
	g[i].bm=15^gbid[i-1];
}
var pac= new Pacman();
var bonus=new Array();
	for (var i=1; i<=4; i++) bonus[i]=0;
var asset = new Ghost();
var assetPorts=new Array();
var movedir=0;
var runThru=false;
var gameOn= false;
var pill= false;
var pillCnt= 0;
var food= 0;
var nLevel= 0;
var nLife=0;
var gStep, gStep2, sStep;
var phaseSet=true;
var bonusLifeCnt=0;
var pacInitDir=0;
var ghostInitDir=0;
var pillPeriode, pillCnt;
var isPause=false;
var restartDialogOn=false;
var gameTimer=null;
var enterTime=0;
var scatterMode, stepCnt, scatterCnt, moved, grenades, shot, shotreleased, blastCnt;

var aSpan= new Array();
var gSpan= new Array();
var gSpan2= new Array();
var sSpan= new Array();

var aSpan3D = new Array();
var gSpan3D= new Array();
var gSpan3D2= new Array();
var sSpan3D= new Array();

var pacStr= {
	'0': ['rr1', 'rr1', 'rr1'],
	'1': ['rr1', 'rr2', 'rr3'],
	'2': ['rl1', 'rl2', 'rl3'],
	'4': ['rb1', 'rb2', 'rb3'],
	'8': ['rf1', 'rf2', 'rf3'],
	'x': ['rx1', 'rr2', 'rx2', 'rb2', 'rx3', 'rl2', 'rx4', 'rf2']
};

var blasterStr = {
	'0': 'rbr',
	'1': 'rbr',
	'2': 'rbl',
	'4': 'rbb',
	'8': 'rbf'
};

var shellStr = {
	'0': 'sr',
	'1': 'sr',
	'2': 'sl',
	'4': 'sb',
	'8': 'sf'
};

var ghostBStr= {
	'1': { '0': 'b1f', '1': 'b1r', '2': 'b1l', '4': 'b1b', '8': 'b1f' },
	'2': { '0': 'b2f', '1': 'b2r', '2': 'b2l', '4': 'b2b', '8': 'b2f' },
	'3': { '0': 'b3f', '1': 'b3r', '2': 'b3l', '4': 'b3b', '8': 'b3f' },
	'4': { '0': 'b4f', '1': 'b4r', '2': 'b4l', '4': 'b4b', '8': 'b4f' },
	'a': { '0': 'baf', '1': 'bar', '2': 'bal', '4': 'bab', '8': 'baf' },
	'n': { '0': 'bnf', '1': 'bnr', '2': 'bnl', '4': 'bnb', '8': 'bnf' },
	'x': 'bx'
};

var ghostAStr= {
	'0': [ 'af1', 'af2', 'af3' ],
	'1': [ 'ar1', 'ar2', 'ar3' ],
	'2': [ 'al1', 'al2', 'al3' ],
	'4': [ 'ab1', 'ab2', 'ab3' ],
	'8': [ 'af1', 'af2', 'af3' ],
	'x': 'ax'
};

var blastStr = [ '', 'blast1', 'blast2', 'blast3', 'blast4', 'blast5' ];

var scatterPhase= [
	[0, 25],
	[60, 30],
	[60, 25],
	[90, 20]
];

var dotsounds = ['doteat1', 'doteat2', 'doteat3'];

var lifeStr='life';

var scatterPhaseCnt;

var gameStatus=0;
var statusCnt=0;
var ghostCnt=0;

var ghostBonus=new Array(200,400,800,1600,300);

var isSpaceTile= {
	pnt:true, x:true, p:true, s:true
};


// constructors

function Ghost() {
	this.r= 0;
	this.c= 0;
	this.s= 0;
	this.d= 0;
	this.p= 0;
	this.pn= 0;
	this.z= 0;
	this.osx=0;
	this.osy=0;
	this.posx=0;
	this.posy=0;
	this.bid=0;
	this.bm=0;
	this.alpha=1;
	this.lc='';
	this.cMovestrat=0;
	this.cMoveahead=0;
	this.joh=0;
	this.pill=false;
	this.scatter=false;
	this.scnt=0;
}

function Pacman() {
	this.r= 0;
	this.c= 0;
	this.p= 0;
	this.pn= 0;
	this.dir= pacInitDir;
	this.md= 0;
	this.dx= 0;
	this.dy= 0;
	this.osx=0;
	this.osy=0;
	this.posx=0;
	this.posy=0;
	this.reversed=false;
	this.lc='';
	this.or=0
}

function Shell() {
	this.r= 0;
	this.c= 0;
	this.dx=0;
	this.dy=0;
	this.osx=0;
	this.osy=0;
	this.posx=0;
	this.posy=0;
}


// basics

function getElement(id) {
	if (document.getElementById) return document.getElementById(id);
	if (document.all) return doucument.all[id];
	return null;
}

function setVisibility(obj, v) {
	obj.style.visibility= (v)? 'visible' : 'hidden';
}

function setOpacity(obj,v) {
	if (!obj) return;
	if (typeof obj.style.opacity != 'undefined') {
		obj.style.opacity=v;
	}
	else if (typeof obj.style.filter != 'undefined') {
		if (!obj.style.filter) {
			if (v<1) obj.style.filter='progid:DXImageTransform.Microsoft.Alpha(Opacity='+Math.floor(v*100)+')';
		}
		else {
			if (v<1) {
				try {
					var f=obj.filters.item('DXImageTransform.Microsoft.Alpha');
					f.opacity = Math.floor(v*100);
					f.enabled = true;
				}
				catch(e) {
					var fs=obj.filters;
					fs.push('progid:DXImageTransform.Microsoft.Alpha(Opacity='+Math.floor(v*100)+')');
				}
			}
			else {
				try {
					obj.filters.item('DXImageTransform.Microsoft.Alpha').enabled = false;
				}
				catch(e) {}
			}
		}
	}
	else if (typeof obj.style.MozOpacity != 'undefined') {
		obj.style.MozOpacity=v;
	}
	else if (typeof obj.style.KhtmlOpacity != 'undefined') {
		obj.style.KhtmlOpacity=v;
	}
}

function setImage(id, img) {
	document.images[id].src=imgRef[img].src;
}

function setSpriteImg(obj, img) {
	if (!imgRef[img]) alert('missing imgRef: '+img);
	obj.src=imgRef[img].src;
}

function moveElement(obj,x,y,z) {
	obj.style.left=x+'px';
	obj.style.top=y+'px';
	obj.style.zIndex=z;
}

function setMaze(r,c,s) {
	elements['t'+r+'_'+c].src=imgRef[s].src;
}

// msie-pre-7 png fixes

function setSpriteImgMsieLe6(obj, img) {
	obj.filters.item(0).src=imgRef[img].src;
}

function setMazeMsieLe6(r,c,s) {
	elements['t'+r+'_'+c].filters.item(0).src=imgRef[s].src;
}


// settings

function setQuality(v) {
	var s1=aStep;
	var s2=gStep;
	var s3=gStep2;
	aStep=settingsQuality[v];
	setSpan();
	pillMinLength=pillMaxLength*aStep-8*pillDecrement;
	pillPeriode=(nLevel<6)? pillMaxLength*aStep : Math.max(pillMinLength, pillMaxLength*aStep-(nLevel-5)*pillDecrement);
	bonusLength=10*aStep;
	setImage('neon_q'+settingsQualityValue, 'neon_lo');
	setImage('neon_q'+v, 'neon_hi');
	settingsQualityValue=v;
	var cf1=aStep/s1;
	var cf2=gStep/s2;
	var cf3=gStep2/s3;
	pac.osx=Math.round(pac.osx*cf1);
	pac.osy=Math.round(pac.osy*cf1);
	for (var i=1; i<=4; i++) {
		var gi=g[i];
		if (gi.s==0) continue;
		if (gi.pill && gi.s==2) {
			gi.osx=Math.round(gi.osx*cf2);
			gi.osy=Math.round(gi.osy*cf2);
		}
		else if (gi.s==3) {
			gi.osx=Math.round(gi.osx*cf3);
			gi.osy=Math.round(gi.osy*cf3);
		}
		else {
			gi.osx=Math.round(gi.osx*cf1);
			gi.osy=Math.round(gi.osy*cf1);
		}
	}
	aSpeed=settingsSpeed[settingsSpeedValue];
	gameDelay=Math.round(aSpeed/aStep);
}

function setSpeed(v) {
	aSpeed=settingsSpeed[v];
	setImage('neon_s'+settingsSpeedValue, 'neon_lo');
	setImage('neon_s'+v, 'neon_hi');
	settingsSpeedValue=v;
	gameDelay=Math.round(aSpeed/aStep);
}

// maze & game setup

function buildMaze(lvl) {
	var r, c, d, f1r, fwr, z, m;
	if (lvl.name) {
		displayMazeName(lvl.name);
	}
	else {
		displayMazeName('');
	}
	m=lvl.maze;
	food=0;
	for (r=1; r<=22; r++) {
		fwr=fw[r];
		f1r=f1[r];
		for (c=1; c<=19; c++) {
			f1r[c]=0;
			z=m[r-1].charAt(c-1);
			if (z=='.') {
				setMaze(r,c,"pnt");
				f1r[c]=9;
				food++;
				fwr[c]=true;
			}
			else {
				setMaze(r,c,z);
				if (z=='p') {
					f1r[c]=8;
					food++;
				}
				fwr[c]=isSpaceTile[z];
			}
		}
	}
	pacInitDir=0;
	if (fw[17][9]) pacInitDir|=2;
	if (fw[17][11]) pacInitDir|=1;
	if (fw[18][10]) pacInitDir|=8;
	if (fw[16][10]) pacInitDir|=4;
	ghostInitDir=0;
	if (fw[9][9]) ghostInitDir|=2;
	if (fw[9][11]) ghostInitDir|=1;
	if (fw[8][10]) ghostInitDir|=4;
	
	// calc directions
	f2=new Array();
	for (r=1; r<=22; r++) {
		f2[r]=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];
		fgh[r]=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];
	}
	for (r=2; r<22; r++) {
		for (c=2; c<19; c++) {
			if (fw[r][c] && (r<10 || r>12 || c<8 || c>12))  {
				d=0;
				if (fw[r-1][c]) d|=4;
				if (fw[r+1][c]) d|=8;
				if (fw[r][c-1]) d|=2;
				if (fw[r][c+1]) d|=1;
				if ((d==3) || (d==12)) d=0;
				f2[r][c]=d;
			}
		}
	}
}

function calcNextNodes() {
	var dirs=t2[15];
	var fm,fr,dx,dy,x,y;
	for (var m=0; m<dirs.length; m++) {
		var d=dirs[m];
		fd=nextNodes[d]=new Array();
		for (var r=1; r<=22; r++) {
			fr=fd[r]=new Array();
			for (var c=1; c<=19; c++) {
				if (f2[r][c] & d) {
					dx=tx[d];
					dy=ty[d];
					y=r;
					x=c;
					while (true) {
						if (y==1) {fr[c]=[21,c]; break;}
						if (y==22) {fr[c]=[2,c]; break;}
						if (x==1) {fr[c]=[r,18]; break;}
						if (x==19) {fr[c]=[r,2]; break;}
						x+=dx;
						y+=dy;
						if (f2[y][x]) {fr[c]=[y,x]; break;}
					}
				}
				else {
					fr[c]=null;
				}
			}
		}
	}
}

function calcHomePaths() {
	var i, d, d2, d3, r, c, p, n;
	var paths=new Array();
	var a=t2[ghostInitDir];
	assetPorts.length=0;
	for (i=0; i<a.length; i++) {
		paths.push([9, 10, a[i]]);
	}
	while (paths.length) {
		var newpaths=new Array();
		for (i=0; i<paths.length; i++) {
			p=paths[i];
			d=p[2];
			r=p[0]+ty[d];
			c=p[1]+tx[d];
			if (r<1) {
				r=22;
			}
			else if (r>22) {
				r=1;
			}
			if (c<1) {
				c=19;
				assetPorts.push(r);
			}
			else if (c>19) {
				c=1;
			}
			if (!fgh[r][c]) {
				d2=f2[r][c];
				d3=t3[d];
				fgh[r][c]=d3;
				if (d2) {
					d2&=(15^d3);
					if (d2) {
						a=t2[d2];
						for (n=0; n<a.length; n++) {
							newpaths.push([r, c, a[n]]);
						}
					}
				}
				else {
					newpaths.push([r, c, d]);
				}
			}
		}
		paths=newpaths;
	}
}


// general


function pHome(initial, initscatter) {
	pill=false; pillCnt=0;
	movedir=0;
	with (pac) {
		r=17; c=10;
		osx=0; osy=ghomeOfs;
		md=0; dir= pacInitDir;
		dx=0; dy=0;
		pn=1; p=0;
		reversed=false;
		pacLast=[r,c];
		pacNext=null;
		lc='';
		or=1;
	}
	dotsound=0;
	if (moved) resetScatter();
	moved=false;
	var sp=sprites.pac;
	setOpacity(sp.img, .1);
	setOpacity(sp.blaster, .1);
	setSpriteImg(sp.img, pacStr[0][0]);
	var pos=mazePos[17][10];
	moveElement(sp.div, pos.x-3, pos.y+ghomeOfs, pos.z+5);
	if (!initial) {
		resetGrenades();
	}
	else if (grenades) {
		setSpriteImg(sp.blaster, blasterStr[0]);
		setVisibility(sp.blaster, true);
	}
	setVisibility(sprites.blast, false);
	blastCnt=0;
	if (initscatter) {
		stepCnt=0;
		scatterMode=true;
		scatterCnt=(initial)? scatterPhase[0][1] : Math.max(15, scatterPhase[0][1]-nLevel*2);
	}
	gameStatus=5;
	if (useSound) playSound((initial || nLife>1)? 'appear':'warning');
}

function gHome(i, initial, up) {
	with (g[i]) {
		for (var k=0; k<gHomePos.length; k++) {
			if (tileFree(i,gHomePos[k][0],gHomePos[k][1])) {
				r=gHomePos[k][0];
				c=gHomePos[k][1];
				break
			}
		};
		osx=0;
		osy=(up)? ghomeOfs:-ghomeOfs;
		s=5;
		p=0; pn=1;
		z= (initial)? Math.max(3, 8-nLevel):2+getRand(3);
		d=0;
		lc='';
		pill=false;
		joh=3;
		alpha=1;
		scatter=scatterMode;
		scnt=0;
		setGhost(i,r,c);
	}
	var gs=sprites.g[i];
	gs.a.style.top='0px';
	setVisibility(gs.a, true);
	setVisibility(gs.b, true);
	setOpacity(gs.a, .1);
	setOpacity(gs.b, .1);
	setVisibility(gs.div, true);
}

function aHome() {
	with (asset) {
		r=assetPorts[Math.floor(Math.random()*assetPorts.length)];
		if (Math.random()>=.5) {
			c=1;
			d=1;
		}
		else {
			c=19;
			d=2;
		}
		osx=0;
		osy=0;
		s=1;
		p=0; pn=1;
	}
	setOpacity(sprites.asset.div, 1);
	setVisibility(sprites.asset.div, true);
}

function resetGrenades() {
	for (var i=1; i<10; i++) setImage('shell'+i,'xx');
	grenades=0;
}

function newGame() {
	if (gameTimer) clearTimeout(gameTimer);
	isPause=false;
	setRestartDialogVisible(false);
	setVisibility(elements.gameover, false);
	setVisibility(elements.gamepaused, false);
	setVisibility(sprites.pac.blaster, false);
	hideShot();
	if (msie) {
		setVisibility(elements.maze,true);
	}
	else {
		setOpacity(elements.maze, 1);
	}
	switch (mazeMode) {
		case 'PacLevels':
			levels=pacLevels;
			break;
		case 'B9Levels':
			levels=b9Levels;
			break;
		case 'SpaceLevels':
			levels=spaceLevels;
			break;
		case 'Shuffle':
		case 'Sequentially':
		default:
			if (!allLevels) allLevels=b9Levels.concat(spaceLevels, pacLevels);
			if (mazeMode=='Shuffle') {
				var b=new Array();
				for (var i=0; i<allLevels.length; i++) b.push({ r: Math.random(), i:i });
				b.sort(levelSorter);
				levels=new Array();
				for (var i=0; i<b.length; i++) levels.push( allLevels[b[i].i] );
			}
			else {
				levels=allLevels;
			}
			break;
	}
	nLife=3;
	setImage('life1',lifeStr);
	setImage('life2',lifeStr);
	setImage('life3','xx');
	setImage('life4','xx');
	setImage('life5','xx');
	nScore=0;
	nLevel=0;
	resetGrenades();
	displayLevel();
	displayScore();
	bonusLifeCnt=0;
	startLevel();
	gameTimer=setTimeout('gameStep()', gameDelay);
}

function levelSorter(a,b) {
	return a.r-b.r;
}

function startLevel() {
	gameOn=false;
	moved=false;
	setVisibility(sprites.pac.div, false);
	for (i=1; i<=4; i++) {
		setVisibility(sprites.g[i].div, false);
		setVisibility(sprites.bonus[i].div, false);
		bonus[i]=0;
	}
	setVisibility(sprites.asset.div, false);
	asset.s=0;
	shotreleased=false;
	runThru=false;
	nLevel++;
	displayLevel();
	displayScore();
	statusCnt=0;
	var cl=nLevel/10;
	g[1].cMovestrat=Math.min(0.85, 0.55+cl);
	g[1].cMoveahead=1;
	g[2].cMovestrat=Math.min(0.75, 0.25+cl);
	g[2].cMoveahead=Math.min(0.65, 0.15+cl);
	g[3].cMovestrat=Math.min(0.7, 0.2+cl);
	g[3].cMoveahead=Math.min(0.5, 0.1+cl);
	g[4].cMovestrat=Math.min(0.85, 0.6+cl);
	g[4].cMoveahead=-1;
	
	pGstrat=Math.min(0.75, 0.25+nLevel/10);
	pGstrat2=Math.min(0.85, 0.5+nLevel/5);
	pGsLookahead=Math.min(0.6, 0.2+nLevel/10);
	pillPeriode=(nLevel<6)? pillMaxLength*aStep : Math.max(pillMinLength, pillMaxLength*aStep-(nLevel-5)*pillDecrement);
	buildMaze(levels[(nLevel-1)%levels.length]);
	calcNextNodes();
	calcHomePaths();
	for (var r=1; r<=22; r++) {
		for (var c=1; c<=19; c++) {
			fft[r][c]=0;
		}
	}
	scatterPhaseCnt=0;
	phaseSet=true;
	pHome(true, true);
	for (var i=1; i<=4; i++) gHome(i, true, true);
	pac.lfx=pac.lfy=0;
	setVisibility(sprites.pac.div, true);
	gameOn=true;
}

function setSpan() {
	for (var n=1-aStep; n<aStep; n++) aSpan[n]= (n==0)? 0 : n/aStep;
	gStep=Math.round(aStep*pillFactor);
	for (n=1-gStep; n<gStep; n++) gSpan[n]= (n==0)? 0 : n/gStep;
	gStep2=Math.round(aStep*eyesFactor);
	for (n=1-gStep2; n<gStep2; n++) gSpan2[n]= (n==0)? 0 : n/gStep2;
	sStep=Math.round(aStep*shellFactor);
	for (n=1-sStep; n<sStep; n++) sSpan[n]= (n==0)? 0 : n/sStep;
	
	var min, a, r, c, dx, dy;
	min=1-aStep;
	for (r=min; r<aStep; r++) {
		a=aSpan3D[r]=new Array();
		dx= (r==0)? 0:-14*r/aStep;
		dy= (r==0)? 0:11*r/aStep;
		for (c=min; c<aStep; c++) {
			if (c==0) {
				a[c]= { x: Math.round(dx), y: Math.round(dy) };
			}
			else {
				a[c] = { x: Math.round(dx + 24*c/aStep), y: Math.round(dy+6*c/aStep) };
			}
		}
	}
	min=1-gStep;
	for (r=min; r<gStep; r++) {
		a=gSpan3D[r]=new Array();
		dx= (r==0)? 0:-14*r/gStep;
		dy= (r==0)? 0:11*r/gStep;
		for (c=min; c<gStep; c++) {
			if (c==0) {
				a[c]= { x: Math.round(dx), y: Math.round(dy) };
			}
			else {
				a[c] = { x: Math.round(dx + 24*c/gStep), y: Math.round(dy+6*c/gStep) };
			}
		}
	}
	min=1-gStep2;
	for (r=min; r<gStep2; r++) {
		a=gSpan3D2[r]=new Array();
		dx= (r==0)? 0:-14*r/gStep2;
		dy= (r==0)? 0:11*r/gStep2;
		for (c=min; c<gStep2; c++) {
			if (c==0) {
				a[c]= { x: Math.round(dx), y: Math.round(dy) };
			}
			else {
				a[c] = { x: Math.round(dx + 24*c/gStep2), y: Math.round(dy+6*c/gStep2) };
			}
		}
	}
	min=1-sStep;
	for (r=min; r<sStep; r++) {
		a=sSpan3D[r]=new Array();
		dx= (r==0)? 0:-14*r/sStep;
		dy= (r==0)? 0:11*r/sStep;
		for (c=min; c<sStep; c++) {
			if (c==0) {
				a[c]= { x: Math.round(dx), y: Math.round(dy) };
			}
			else {
				a[c] = { x: Math.round(dx + 24*c/sStep), y: Math.round(dy+6*c/sStep) };
			}
		}
	}
}

function limitOffsets(obj,limit) {
	if (obj.osx>=limit) obj.osx=limit-1;
	if (obj.osy>=limit) obj.osy=limit-1;
	if (obj.osx<=-limit) obj.osx=1-limit;
	if (obj.osy<=-limit) obj.osy=1-limit;
}

function getRand(x) {
	return Math.floor(Math.random() * x);
}

function trunkBy(v,m) {
	v%=m;
	return (v==0)? m:v;
}

function tileFree(n, r,c) {
	if (n) {
		return (fft[r][c]&g[n].bm)? false:true;
	}
	else {
		return (fft[r][c])? false:true;
	}
}

function isCollision(x1,y1,x2,y2, radius) {
	return (Math.abs(x1-x2)+Math.abs(y1-y2)<radius);
}

function addScore(n) {
	nScore+=n;
	bonusLifeCnt+=n;
	if (bonusLifeCnt>=bonusLifeScore) {
		bonusLife();
		bonusLifeCnt-=bonusLifeScore;
	}
	displayScore();
}

function displayLevel() {
	elements.leveldisplay.innerHTML=nLevel;
}

function displayScore() {
	elements.scoredisplay.innerHTML=nScore;
}

function displayMazeName(t) {
	elements.mazedisplay.innerHTML=(t)? 'Now playing: &raquo;'+t+'&laquo;' : '';
}


// main

function gameStep() {
	if (gameTimer) clearTimeout(gameTimer);
	var now=new Date();
	enterTime=now.getTime();
	if (gameOn) {
		phaseSet=(!phaseSet);
		if (moved && !pill && gameStatus==0 && ++stepCnt>=aStep) {
			stepCnt=0;
			if (--scatterCnt<0) setScatter();
		}
		switch(gameStatus) {
			case 0: doMove(); break;
			case 1: resetGhost(); break;
			case 2: resetPac(); return;
			case 3: endLevel(); break;
			case 4: startLevel(); break;
			case 5: enterPac(); break;
		}
	}
	shotreleased=false;
	if (gameOn || isPause) gameTimer=setTimeout('reLoop()', 1);
}

function reLoop() {
	if (gameTimer) clearTimeout(gameTimer);
	var now=new Date();
	var delay = gameDelay + enterTime - now.getTime();
	gameTimer=setTimeout('gameStep()', (delay>0)? delay:1);
}

function setScatter() {
	if (scatterMode) {
		if (scatterPhaseCnt < scatterPhase.length-1) scatterPhaseCnt++;
		scatterMode=false;
		scatterCnt=scatterPhase[scatterPhaseCnt][0]+nLevel*10;
		for (var i=1; i<=4; i++) {
			g[i].scnt=0;
			g[i].scatter=false;
		}
	}
	else {
		scatterMode=true;
		scatterCnt=Math.max(10, scatterPhase[scatterPhaseCnt][1] - (nLevel-1));
		for (var i=1; i<=4; i++) {
			g[i].scnt=0;
			g[i].scatter=true;
		}
	}
}

function resetScatter() {
	if (scatterMode) {
		setScatter();
	}
	else {
		scatterCnt=scatterPhase[scatterPhaseCnt][0]+nLevel*10;
	}
}

function enterPac() {
	var sp=sprites.pac;
	pac.osy--;
	if (pac.osy==0) {
		setOpacity(sp.img,1);
		setOpacity(sp.blaster,1);
		pac.osy=0;
		gameStatus=0;
	}
	else {
		var a=.1+.9*(1-(pac.osy/ghomeOfs));
		setOpacity(sp.img, a);
		setOpacity(sp.blaster, a);
	}
	var p = mazePos[pac.r][pac.c];
	moveElement(sp.div, p.x-3, p.y+pac.osy, p.z+5);
	gmove();
}

function doMove() {
	var sb=sprites.bonus;
	for (var i=1; i<=4; i++) {
		if (bonus[i]>0) {
			bonus[i]--;
			if (bonus[i]==0) {
				setVisibility(sb[i].div, false);
			}
			else {
				setOpacity(sb[i].div, bonus[i]/bonusLength);
			}
		}
	}
	if (blastCnt>0) {
		blastCnt--;
		if (blastCnt>0) {
			if (blastCnt%3==0) setSpriteImg(sprites.blast, blastStr[Math.round(blastCnt/3)]);
		}
		else {
			setVisibility(sprites.blast, false);
		}
	}
	with (pac) {
		var oor=or;
		if (osx+osy==0) {
			pMove();
		}
		else if (useInstantTurns && reversed==false && movedir && movedir==t3[md] && f1[r][c]==0) {
			if (dx) dx=-dx;
			if (dy) dy=-dy;
			md=t3[md];
			movedir=0;
			reversed=true;
			var temp=pacNext;
			pacNext=pacLast;
			pacLast=temp;
			touchX=window.touchLastX;
			touchY=window.touchLastY;
		}
		if (runThru) {
			osx+=dx;
			osy+=dy;
			if ((c+dx)%20==0) osx=0;
			if ((r+dy)%23==0) osy=0;
			osx%=aStep;
			osy%=aStep;
			if (reversed==false) {
				if (osx==0) c=trunkBy(c+dx,19);
				if (osy==0) r=trunkBy(r+dy,22);
			};
			if (phaseSet) {
				p+=pn;
				if (p==2) pn=-1;
				if (p==0) pn=1;
			};
			setPac(r,c,pacStr[md][p]);
			if (osx+osy==0 && f2[r][c]) dir=f2[r][c];
		}
		else if (moved && movedir) {
			p=1;
			or=movedir;
			setPac(r,c,pacStr[or][1]);
		}
		if (grenades && oor!=or) setSpriteImg(sprites.pac.blaster, blasterStr[or]);
	}
	var r=pac.r+Math.round(pac.osy/aStep*.75);
	var c=pac.c+Math.round(pac.osx/aStep*.75);
	if (f1[r][c]>=8) {
		setMaze(r,c,'x');
		if (f1[r][c]==8) {
			pill=true;
			for (var i=1; i<=4; i++) {
				var gi=g[i];
				if (!gi.pill && gi.s<3) {
					gi.pill=true;
					translateGPos(i,false);
				}
			}
			pillCnt=pillPeriode;
			addScore(40);
			ghostCnt=0;
			if (useSound) playSound('pillbeam');
			if (scatterMode) setScatter();
		}
		else {
			addScore(15);
			if (useSound) {
				playSound((dotsounds[dotsound])?'doteat1':'doteat2');
				dotsound=(dotsound+1)%3;
			}
		}
		f1[r][c]=0;
		food--;
		if (food==0) {
			statusCnt=blinkSteps*blinkRate;
			gameStatus=3;
			g[1].alpha=.75;
			for (i=1; i<=4; i++) {
				var gs=sprites.g[i];
				setOpacity(gs.a, .75);
				setOpacity(gs.b, .75);
			}
			if (useSound) playSound('endlevel');
			hideShot();
			return;
		}
	}
	gmove();
	if (shot) {
		shotMove();
	}
	else if (shotreleased && grenades && fireShot()) {
		if (grenades<10) setImage('shell'+grenades, 'xx');
		grenades--;
		if (!grenades) setVisibility(sprites.pac.blaster, false);
	}
	aMove();
	checkHits();
	if (gameStatus>0) return;
	if (pill) {
		pillCnt--;
		if (pillCnt==0) {
			pill=false;
			for (i=1; i<=4; i++) {
				var gi=g[i];
				if (gi.pill) {
					gi.pill=false;
					if (gi.s!=4) translateGPos(i,true);
				}
			}
		}
	}
}


// pacman

function setPac(r,c,s) {
	pac.posx=c+aSpan[pac.osx];
	pac.posy=r+aSpan[pac.osy];
	if (s!=pac.lc) {
		setSpriteImg(sprites.pac.img, s);
		pac.lc=s;
	}
	var p = mazePos[r][c];
	var ofs = aSpan3D[pac.osy][pac.osx];
	moveElement(sprites.pac.div, p.x+ofs.x-3, p.y+ofs.y, p.z+5);
}

function pMove() {
	with (pac) {
		if (dir&movedir) {
			md= dir&movedir;
			touchX=window.touchLastX;
			touchY=window.touchLastY;
			moved=true;
		}
		else {
			md&=dir;
			if (md==0) runThru=false;
		}
		if (md) {
			runThru=true;
			dx=(md&3);
			dy=(md&12);
			if (dx) {
				dir=3;
				dx=tx[dx];
			}
			if (dy) {
				dir=12;
				dy=ty[dy];
			}
			or=md;
		}
		reversed=false;
		if (f2[r][c]) {
			setPacNextNode();
			pacLast=[r,c];
		}
	}
}

function setPacNextNode() {
	with (pac) {
		if (md) {
			var n=nextNodes[md][r][c];
			if (n) {
				var d=f2[n[0]][n[1]] & (15^t3[md]);
				while (d && t2[d].length<2) {
					var nn=nextNodes[d][n[0]][n[1]];
					if (nn) {
						n=nn;
						d=f2[n[0]][n[1]] & (15^t3[d]);
					}
					else {
						break;
					}
				}
				pacNext=n;
				return;
			}
		}
		pacNext=null;
	}
}


// asset

function aMove() {
	if (gameOn) {
		if (asset.s==0) {
			if (moved && Math.random()< ((grenades)? assetProbability2:assetProbability1)) {
				aHome();
				setAsset();
				if (useSound) playSound('assetenter');
			}
		}
		else {
			with (asset) {
				if (osx+osy==0) {
					var x= f2[r][c];
					if (x>0) {
						var k= x&(15^t3[d]);
						d=t2[k][getRand(t2[k].length)];
					}
				}
				osy=(osy+ty[d])%gStep;
				osx=(osx+tx[d])%gStep;
				if (osx==0) c+=tx[d];
				if (osy==0) r+=ty[d];
				if (c==0 || c==20 || r==0 || r==23) {
					s=0;
					setVisibility(sprites.asset.div, false);
					if (useSound) playSound('assetleave');
				}
				else {
					setAsset();
				}
				if (phaseSet) {
					p+=pn;
					if (p==3) pn=-1;
					if (p==0) pn=1;
				}
			}
		}
	}
}

function setAsset() {
	asset.posx=asset.c+gSpan[asset.osx];
	asset.posy=asset.r+gSpan[asset.osy];
	var p = mazePos[asset.r][asset.c];
	var ofs = gSpan3D[asset.osy][asset.osx];
	moveElement(sprites.asset.div, p.x+ofs.x+12, p.y+ofs.y+16-asset.p, p.z);
}


// shot

function fireShot() {
	shot=new Shell();
	var d=pac.or || 2;
	var dx=shot.dx=tx[d];
	var dy=shot.dy=ty[d];
	var r=shot.r=pac.r+dy;
	var c=shot.c=pac.c+dx;
	if (r<=1 || r>=22 || c<=1 || c>=19) return false;
	shot.osx=Math.round(pac.osx/shellFactor);
	shot.osy=Math.round(pac.osy/shellFactor);
	setSpriteImg(sprites.shot, shellStr[d]);
	setShot();
	setVisibility(sprites.shot, true);
	if (useSound) playSound('shoot');
	return true;
}

function setShot() {
	shot.posx=shot.c+sSpan[shot.osx];
	shot.posy=shot.r+sSpan[shot.osy];
	var p = mazePos[shot.r][shot.c];
	var ofs = gSpan3D[shot.osy][shot.osx];
	moveElement(sprites.shot, p.x+ofs.x-3, p.y+ofs.y, p.z+5);
	var hit=false;
	var x=0, y=0, z=0;
	for (var i=1; i<=4; i++) {
		var gi=g[i];
		if (gi.s==2 && isCollision(gi.posx,gi.posy, shot.posx,shot.posy, 0.9)) {
			ghostEnd(i, 4);
			p=mazePos[gi.r][gi.c];
			ofs=aSpan3D[gi.osy][gi.osx];
			if (x) {
				x= (x+p.x+ofs.x)/2;
				y= (y+p.y+ofs.y)/2;
				if (p.z>z) z=p.z;
			}
			else {
				x=p.x+ofs.x;
				y=p.y+ofs.y;
				z=p.z;
			}
			hit=true;
		}
	}
	if (hit) {
		blastCnt=blastStr.length-1;
		setSpriteImg(sprites.blast, blastStr[blastCnt]);
		blastCnt*=3;
		moveElement(sprites.blast, x-24, y+3, z+6);
		setVisibility(sprites.blast, true);
		setTimeout('hideShot()',1);
		if (useSound) playSound('bothit');
	}
}

function shotMove() {
	with (shot) {
		osy=(osy+dy)%sStep;
		osx=(osx+dx)%sStep;
		if (osx==0) c+=dx;
		if (osy==0) r+=dy;
		if (c==0 || r==0 || c==20 || r==23) {
			hideShot();
			if (useSound) playSound('voidshot');
		}
		else {
			setShot();
		}
	}
}

function hideShot() {
	setVisibility(sprites.shot, false);
	shot=null;
}


// ghosts

function setGhost(i,r,c) {
	var eyes;
	var gi=g[i];
	var s=gi.s;
	var gc, ofs, bs;
	var p = mazePos[gi.r][gi.c];
	if (gi.pill && s<3) {
		if (s==0) {
			gi.posx=c;
			gi.posy=r;
			ofs = {x:0,y:0};
		}
		else {
			gi.posx=c+gSpan[gi.osx];
			gi.posy=r+gSpan[gi.osy];
			ofs=gSpan3D[gi.osy][gi.osx];
		}
		if (pillCnt>4*aStep) {
			gc=ghostBStr.a;
		}
		else {
			gc=(pillCnt%6<3)? ghostBStr.n:ghostBStr.a;
		}
	}
	else if (s==0) {
		gi.posx=c;
		gi.posy=r;
		ofs = {x:0,y:0};
		gc=ghostBStr[i];
	}
	else if (s==3) {
		gi.posx=c+gSpan2[gi.osx];
		gi.posy=r+gSpan2[gi.osy];
		ofs=gSpan3D2[gi.osy][gi.osx];
	}
	else if (s==5) {
		gs=sprites.g[i];
		bs=ghostBStr[i][0];
		if (gi.lc!=bs) {
			gi.lc=bs;
			setSpriteImg(gs.bi, bs);
		}
		moveElement(gs.div, p.x, p.y+gi.osy, p.z+i);
		fft[gi.r][gi.c]|=gi.bid;
		return;
	}
	else {
		gi.posx=c+aSpan[gi.osx];
		gi.posy=r+aSpan[gi.osy];
		ofs=aSpan3D[gi.osy][gi.osx];
		gc=ghostBStr[i];
	}
	var gs=sprites.g[i];
	if (s<3) {
		var d=(s==0)? 0:gi.d;
		var bs=gc[d];
		if (bs!=gi.lc) {
			setSpriteImg(gs.bi, bs);
			gi.lc=bs;
		}
		setSpriteImg(gs.ai, ghostAStr[d][gi.p]);
		fft[gi.r][gi.c]|=gi.bid;
	}
	moveElement(gs.div, p.x+ofs.x, p.y+ofs.y, p.z+i);
}

function gmove() {
	for (i=1; i<=4; i++) {
		if (gameOn) {
			with (g[i]) {
				fft[r][c]&=bm;
				if (phaseSet) {
					p+=pn;
					if (p==2) pn=-1;
					if (p==0) pn=1;
				}
				switch (s) {
					case 1: gMove1(i); break;
					case 2: gMove2(i); break;
					case 3: gMove3(i); break;
					case 4: gMove4(i); break;
					case 5: gMove5(i); break;
					default: gMove0(i); break;
				}
			}
		}
		if (g[i].s!=4) displayGhost(i);
	}
}

function displayGhost(i) {
	with (g[i]) {
		setGhost(i,r,c);
	}
}

function gMove0(i) {
	with (g[i]) {
		if (moved) {
			if (r==10 && tileFree(i,9,10)) {
				s++;
				d=4;
				lc='';
				z=0;
			}
			if (r==11 && c==10 && tileFree(i,10,10)) {
				if (z==0) {
					d=4;
					if (--osy==-aStep) {
						osy=0;
						r=10;
					}
				}
				else if (stepCnt==0) {
					z--;
				}
			}
			else if (r==11 && c==9 && tileFree(i,11,10)) {
				d=2;
				if (++osx==aStep) {
					osx=0;
					c=10;
				}
			}
			else if (r==11 && c==11 && tileFree(i,11,10)) {
				if (--osx==-aStep) {
					osx=0;
					c=10;
				}
			}
		}
	}
}

function gMove1(i) {
	with (g[i]) {
		if (tileFree(i,9,10)) {
			if (osy==0) osy--
			else {
				osy--;
				if (osy==-aStep) {
					r=9;
					c=10;
					osx=osy=0;
					if (scatter) {
						gmoveScatter(i, ghostInitDir);
					}
					else {
						d=t2[ghostInitDir][getRand(t2[ghostInitDir].length)];
					}
					s++;
				}
			}
		}
	}
}

function gMove2(i) {
	with (g[i]) {
		if (osx+osy==0) {
			var x= f2[r][c];
			if (joh) {
				joh--;
				x&=11;
			}
			if (x>0) {
				var gdm= x&(15^t3[d]);
				if (scatter && !pill) {
					gmoveScatter(i,gdm);
				}
				else if (i==3 && !pill && scatterCnt%4) {
					var delta=Math.abs(pac.r-r)+Math.abs(pac.c-c);
					if (delta>10 || Math.random()>=cMovestrat) {
						gmoveRand(i,gdm);
					}
					else {
						gmoveStrat(i,gdm);
					}
				}
				else if (Math.random()<cMovestrat) {
					gmoveStrat(i,gdm);
				}
				else {
					gmoveRand(i,gdm);
				}
			}
			if (d>0) {
				if (tileFree(i,trunkBy(r+ty[d],22),trunkBy(c+tx[d],19))) {
					gSet(i);
				}
				else {
					reverseStuck(i,x);
				}
			}
		}
		else {
			gSet(i);
		}
	}
}

function gMove3(i) {
	with (g[i]) {
		if (osx+osy==0) {
			if (r==9 && c==10) {
				setVisibility(sprites.g[i].div, false);
				gHome(i, false, false);
				return;
			}
			d= fgh[r][c];
		}
		gSet(i);
	}
}

function gMove4(i) {
	var gi=g[i];
	gi.z--;
	var gs=sprites.g[i];
	if (gi.z==0) {
		gi.s=3;
		var cf=gStep2/gStep;
		gi.osx=Math.round(gi.osx*cf);
		gi.osy=Math.round(gi.osy*cf);
		var hd = fgh[gi.r][gi.c];
		if (((gi.d & 3) && (hd & 3)) || ((gi.d & 12) && (hd & 12))) gi.d=hd;
		setVisibility(gs.a, false);
		setGhost(i,gi.r,gi.c);
		setOpacity(gs.a,1);
	}
	else {
		gi.alpha-= (gi.z<ghostResetDelay/2)? ghostResetDelta*2 : ghostResetDelta;
		setOpacity(gs.a, gi.alpha);
		var st=sprites.g[i].a.style;
		st.top=(parseInt(st.top)+1)+'px';
	}
}

function gMove5() {
	var gi=g[i];
	gi.osy+= (gi.osy>0)? -1:1;
	if (gi.osy==0) {
		setOpacity(sprites.g[i].a,1);
		setOpacity(sprites.g[i].b,1);
		gi.osy=0;
		gi.s=0;
		gi.p=Math.floor(Math.random()*3);
		gi.pn = (gi.p==2)? -1:1;
	}
	else {
		var a=.1+.9*(1-Math.abs(gi.osy)/ghomeOfs);
		a*=a;
		setOpacity(sprites.g[i].a, a);
		setOpacity(sprites.g[i].b, a);
	}
}

function gSet(i) {
	with (g[i]) {
		osy+=ty[d];
		osx+=tx[d];
		if (s==3) {
			osx%=gStep2;
			osy%=gStep2;
		}
		else if (pill && s==2) {
			osx%=gStep;
			osy%=gStep;
		}
		else {
			osx%=aStep;
			osy%=aStep;
		}
		if ((c==1 && tx[d]==-1) || (c==19 && tx[d]==1)) osx=0;
		if ((r==1 && ty[d]==-1) || (r==22 && ty[d]==1)) osy=0;
		if (osx==0) c=trunkBy(c+tx[d],19);
		if (osy==0) r=trunkBy(r+ty[d],22);
	}
}

function gmoveRand(i,k) {
	g[i].d=t2[k][getRand(t2[k].length)];
}

function gmoveStrat(i,gdm) {
	var desx, desy, px, py;
	var gi=g[i];
	if (gi.pill) {
		desy=gi.r-pac.r;
		desx=gi.c-pac.c;
	}
	else if (pacNext && Math.random()<gi.cMoveahead) {
		py=pacNext[0];
		px=pacNext[1];
		desy=py-gi.r;
		desx=px-gi.c;
		if (desx==0 && desy==0) {
			desy=pac.r-gi.r;
			desx=pac.c-gi.c;
		}
	}
	else {
		desy=pac.r-gi.r;
		desx=pac.c-gi.c;
	}
	var nd=0;
	if (desx!=0) nd= (desx>0)? 1:2;
	if (desy!=0) nd|= (desy>0)? 8:4;
	nd&=gdm;
	gmoveRand(i, (nd)? nd:gdm);
}

function gmoveScatter(i,gdm) {
	var gi=g[i];
	var p=scatterPos[i];
	var desx=p[0]-gi.c;
	var desy=p[1]-gi.r;
	if (gi.scnt) {
		if (--gi.scnt==0) gi.scatter=false;
	}
	else if (Math.abs(desx)+Math.abs(desy)<3) {
		gi.scnt=4;
	}
	var nd=0;
	if (desx!=0) nd= (desx>0)? 1:2;
	if (desy!=0) nd|= (desy>0)? 8:4;
	var dxy=Math.abs(desx)-Math.abs(desy);
	nd&=gdm;
	if (dxy<-2 && nd&12) {
		nd&=12;
	}
	else if (dxy>2 && nd&3) {
		nd&=3;
	}
	gmoveRand(i,(nd)? nd:gdm);
}

function reverseStuck(i,x) {
	with (g[i]) {
		if (x==0) {
			if (tileFree(i,trunkBy(r-ty[d],22),trunkBy(c-tx[d],19))) d=t3[d];
		}
		else {
			var vd= t2[x][getRand(t2[x].length)];
			if (tileFree(i,r+ty[vd],c+tx[vd])) {
				d=vd;
				gSet(i);
			}
		}
	}
}

function translateGPos(i,reset) {
	with (g[i]) {
		if (s==3) return;
		if ((reset) && (s==2)) {
			osx= Math.round(osx/pillFactor-tx[d]*.1);
			osy= Math.round(osy/pillFactor-ty[d]*.1);
			limitOffsets(g[i], aStep);
		}
		else if (s==2) {
			osx= Math.round(osx*pillFactor+tx[d]*.1);
			osy= Math.round(osy*pillFactor+ty[d]*.1);
			limitOffsets(g[i], gStep);
		}
		lc='';
	}
}

// hit-test

function checkHits() {
	var crash=false;
	var ghostcatch=false;
	if (asset.s && isCollision(asset.posx,asset.posy, pac.posx,pac.posy, 0.9)) {
		setVisibility(sprites.asset.div, false);
		asset.s=0;
		if (!grenades) {
			setVisibility(sprites.pac.blaster, true);
			setSpriteImg(sprites.pac.blaster, blasterStr[pac.or]);
			if (useSound) setTimeout("playSound('grabblaster')",110);
		}
		if (useSound) playSound('assetpick');
		grenades++;
		if (grenades<10) setImage('shell'+grenades, 'shell');
	}
	for (i=1; i<=4; i++) {
		var gi=g[i];
		if (gi.s==2 && isCollision(gi.posx,gi.posy, pac.posx,pac.posy, 0.9)) {
			if (gi.pill) {
				ghostEnd(i, ghostCnt);
				if (ghostCnt<3) ghostCnt++;
				ghostcatch=true;
			}
			else {
				crash=true;
				setOpacity(sprites.g[i].a, .5);
				setOpacity(sprites.g[i].b, .5);
			}
		}
	}
	if (crash) {
		setSpriteImg(sprites.pac.img, 'rx0');
		setVisibility(sprites.pac.blaster, false);
		if (blastCnt) {
			setVisibility(sprites.blast, false);
			blastCnt=0;
		}
		hideShot();
		pac.p=0;
		gameStatus=2;
		if (useSound) playSound('pacend');
	}
	else if (ghostcatch) {
		gameStatus=1;
		statusCnt=2;
		if (useSound) playSound('ghostcatch');
	}
}

function ghostEnd(i, bi) {
	var gi=g[i];
	var gs=sprites.g[i];
	var b=sprites.bonus[i];
	var pos = mazePos[gi.r][gi.c];
	var ofs=gSpan3D[gi.osy][gi.osx];
	var ofs2 = i*3;
	bonus[i]=bonusLength;
	moveElement(b.div, pos.x+ofs.x+ofs2+10, pos.y+ofs.y-ofs2+12, pos.z+5);
	setSpriteImg(b.img, 'bonus'+bi);
	setOpacity(b.div, 1);
	setVisibility(b.div, true);
	addScore(ghostBonus[bi]);
	translateGPos(i,true);
	setSpriteImg(gs.bi, ghostBStr.x);
	setSpriteImg(gs.ai, ghostAStr.x);
	gi.lc=ghostBStr.x;
	setOpacity(gs.a, ghostResetAlpha);
	setOpacity(gs.b, 1);
	gi.alpha=ghostResetAlpha;
	gi.z=ghostResetDelay;
	gi.s=4;
	fft[gi.r][gi.c]&=gi.bm;
}

function resetGhost() {
	statusCnt--;
	if (statusCnt==0) gameStatus=0;
}

function resetPac() {
	if (gameTimer) clearTimeout(gameTimer);
	pac.p++;
	if (pac.p<=25) {
		var sp=sprites.pac;
		if (pac.p>1) setSpriteImg(sp.img, pacStr.x[pac.p%8]);
		setOpacity(sp.img, 1-pac.p/25);
		var st=sp.div.style;
		st.top=(parseInt(st.top)+1)+'px';
		gameTimer=setTimeout('resetPac()', 98-pac.p);
	}
	else {
		nLife--;
		if (nLife>0) {
			setImage('life'+nLife,'xx');
			pHome(false, allwaysStartInScatterMode);
			for (var i=1; i<=4; i++) {
				var gi=g[i];
				fft[gi.r][gi.c]&=gi.bm;
				gHome(i, false, true);
			}
			setVisibility(sprites.asset.div, false);
			asset.s=0;
			gameTimer=setTimeout('gameStep()', 100);
		}
		else gameOver();
	}
}

function bonusLife() {
	if (nLife<6) {
		setImage('life'+nLife,lifeStr);
		nLife++;
		if (useSound) playSound('bonuslife');
	}
}

function gameOver() {
	gameOn=false;
	gameStatus=-1;
	setOpacity(elements.gameover, .1);
	setVisibility(elements.gameover, true);
	setVisibility(sprites.pac.div, false);
	setVisibility(elements.gamepaused, false);
	for (var i=1; i<=4; i++) {
		var gs=sprites.g[i];
		setOpacity(gs.a, .6);
		setOpacity(gs.b, .6);
	}
	if (asset.s) setOpacity(sprites.asset.div, .6);
	statusCnt=.1
	gameTimer=setTimeout('showGameOver()', 8);
	if (useSound) playSound('scifi');
}

function showGameOver() {
	if (statusCnt<1) {
		statusCnt+=.01;
		setOpacity(elements.gameover, statusCnt);
		gameTimer=setTimeout('showGameOver()', 8);
	}
}

function endLevel() {
	if (statusCnt>0) {
		var a=g[1].alpha-=.015;
		for (var i=1; i<=4; i++) {
			setOpacity(sprites.g[i].a, a);
			setOpacity(sprites.g[i].b, a);
		}
		if (asset.s) setOpacity(sprites.asset.div, a);
		if (statusCnt%blinkRate==0) {
			if (msie || window.opera) {
				setVisibility(elements.maze, ((statusCnt/blinkRate)%2==blinkSteps%2)? false:true);
			}
			else {
				if ((statusCnt/blinkRate)%2==blinkSteps%2) {
					setOpacity(elements.maze, 0.6);
				}
				else {
					setOpacity(elements.maze, 1);
				}
			}
		}
		statusCnt--;
		if (statusCnt==0) {
			if (msie || window.opera) {
				setVisibility(elements.maze,true);
			}
			else {
				setOpacity(elements.maze, 1);
			}
			for (var i=1; i<=4; i++) {
				var gs=sprites.g[i];
				setVisibility(gs.a, false);
				setVisibility(gs.b, false);
				setVisibility(gs.div, false);
			}
			blastCnt=0;
			setVisibility(sprites.blast, false);
			setVisibility(sprites.asset.div, false);
			setPac(pac.r, pac.c, pacStr[pac.md][2]);
			statusCnt--;
			if (useSound) playSound('leavelevel');
		}
	}
	else {
		var sp=sprites.pac;
		var st=sp.div.style;
		var p=parseInt(st.top)-4;
		st.top=p+'px';
		if (p<=0) {
			statusCnt=0;
			gameStatus=4;
		}
		else if (p<40) {
			var a=p/40;
			setOpacity(sp.img, a);
			setOpacity(sp.blaster, a);
		}
	}
}

function doPause() {
	if (gameStatus>=0) {
		if (gameOn) {
			setVisibility(elements.gamepaused, true);
			gameOn=false;
			isPause=true;
		}
		else {
			setVisibility(elements.gamepaused, false);
			gameOn=true;
			isPause=false;
		}
	}
}

function showRestartDialog() {
	if (gameTimer) clearTimeout(gameTimer);
	setRestartDialogVisible(true);
}

function hideRestartDialog(ok) {
	setRestartDialogVisible(false);
	if (ok) {
		setTimeout('newGame()', 10);
	}
	else {
		setTimeout('reLoop()', 10);
	}
}

function setRestartDialogVisible(v) {
	setVisibility(elements.restartdialog, v);
	setVisibility(elements.dialogscreen, v);
	elements.dialogscreen.display= (v)? 'block':'none';
	if (v) setOpacity(elements.dialogscreenimg, .25);
	restartDialogOn=v;
}


// keyboard

function enableKeyboard() {
	if (document.addEventListener) document.addEventListener("keypress", keyHandler, true)
	else {
		if (self.Event && self.Event.KEYPRESS) document.captureEvents(Event.KEYPRESS);
		document.onkeypress = keyHandler;
	}
	window.document.onkeydown=keyFix;
}

function keyFix(e) {
	// remap some keyCodes
	if (window.event) {
		if (window.event.ctrlKey || window.event.metaKey || window.event.altKey) return true;
		var k=window.event.keyCode;
		if (k==8) keyHandler({which:8})
		else if (k==37) keyHandler({which:28})
		else if (k==39) keyHandler({which:29})
		else if (k==38) keyHandler({which:30})
		else if (k==40) keyHandler({which:31})
		//else if (k==27) keyHandler({which:27})
		else if (k>=57373 && k<=57376) {
			if (k==57373) keyHandler({which:30})
			else if (k==57374) keyHandler({which:31})
			else if (k==57375) keyHandler({which:28})
			else if (k==57376) keyHandler({which:29});
		}
		else {
			window.event.cancleBubble=false;
			return true;
		}
		if (window.event.preventDefault) window.event.preventDefault();
		if (window.event.stopPropagation) window.event.stopPropagation();
		window.event.cancleBubble=true;
		window.event.returnValue=false;
		return false;
	}
	return true;
}

var keyLock=false;

function keyHandler(e) {
	if (keyLock) return;
	var k;
	var ctrl=false;
	if (e) {
		k=e.which;
		ctrl=(e.ctrlKey || e.metaKey || e.altKey || e.metaKey || e.modifiers);
	}
	else if (window.event) {
		k=window.event.keyCode;
		ctrl= (window.event.ctrlKey || window.event.altKey || window.event.metaKey);
	}
	else return true;
	if (ctrl)  return true;
	if (k=='') {
		// map specials
		if (e==null) e=window.event;
		if (e.charCode==0 && e.keyCode) {
			if (e.keyCode==37) k=28
			else if (e.keyCode==39) k=29
			else if (e.keyCode==38) k=30
			else if (e.keyCode==40) k=31
			else if (e.keyCode==27) k=27;
		}
	}
	var ch= (k>=32 && k<127)? String.fromCharCode(k):'';
	ch=ch.toLowerCase();
	
	if (restartDialogOn) {
		if (ch=='n' || k==27) {
			hideRestartDialog(false);
		}
		else if (ch=='y' || k==13) {
			hideRestartDialog(true);
		}
	}
	else {
		if (ch=="8" || ch=="w" || ch=="i" || k==30) {
			movedir=4;
		}
		else if (ch=="4" || ch=="a" || ch=="j" || k==28) {
			movedir=2;
		}
		else if (ch=="6" || ch=="d" || ch=="l" || k==29) {
			movedir=1;
		}
		else if (ch=="5" || ch=="s" || ch=="k" || k==31 || ch=="2" || k==98) {
			movedir=8;
		}
		else if (ch==" " || ch=="0") {
			shotreleased=true;
		}
		else if (ch=="p" || k==27) {
			doPause();
		}
		else if (ch=="n") {
			if ((gameOn || isPause) && nScore>0) {
				showRestartDialog();
			}
			else {
				newGame();
			}
		}
	}
	
	if (window.event) e=window.event;
	if (e.preventDefault) e.preventDefault();
	if (e.stopPropagation) e.stopPropagation();
	e.cancleBubble=true;
	e.returnValue=false;
	return false;
}

// trigger

setTimeout('init()', 500);


onunload=function() { elements=sprites=null; }

// eof