/*
  JavaScript-MsPacMan 3D
  v. 1.01
  (c) Norbert Landsteiner 1996-2009; www.masswerk.at
  (based on "JavaScript-PacMan" and "JavaScript-PacMan 2", all (c) 1996-2009 N. Landsteiner)
*/

// preload & setup

var elements = new Object();

var pacimages = {
	general: {
		png: [
			'x'
		],
		gif: [
			'xx', 'newgame_lo', 'newgame_hi', 'newgame_dn', 'neon_lo', 'neon_hi'
		]
	},
	mspacman: {
		png: [
			'g11', 'g12', 'g13', 'g21', 'g22', 'g23', 'g31', 'g32', 'g33',
			'g41', 'g42', 'g43', 'ga1', 'ga2', 'ga3', 'gn1', 'gn2', 'gn3', 'gx',
			'e0', 'e1', 'e2', 'ea0', 'ea1', 'ea2', 'eh1', 'eh2', 'eh4', 'eh8',
			'ex0', 'ex1', 'ex2', 'ex4', 'ex8',
			'mpb1', 'mpf1', 'mpf2', 'mpf3', 'mpl1', 'mpl2', 'mpl3', 'mpr1', 'mpr2', 'mpr3',
			'mpx1', 'mpx2', 'mpx3', 'mpx4', 'mpx5', 'mpx6', 'mpx7', 'mpx8',
			'bonus0', 'bonus1', 'bonus2', 'bonus3',
			'bonus4', 'bonus10', 'bonus6', 'bonus7', 'bonus8', 'bonus11', 'bonus12',
			'f1', 'f2', 'f3', 'f7', 'f8', 'f9', 'f10'
		],
		gif: [
			'mlife',
			'f1s', 'f2s', 'f3s', 'f7s', 'f8s', 'f9s', 'f10s',
			'gameover', 'gamepaused', 'ready',
			'attr_light1', 'attr_light0', 'attr_g1', 'attr_g2', 'attr_g3', 'attr_g4',
			'attr_with', 'attr_starring', 'attr_mspacman', 'attr_copystatement'
		]
	}
};
var tileimages = [
	'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'k', 'l', 'm', 'n',
	'o', 't', 'u', 'v', 'w', 'y', 'z'
];
var foodimages = ['p', 'pnt'];

var imgRef, imgCnt, imgTotal, tileRef, foodRef;
var imgPath='mspac3dimgs/';
var tileImgPaths=['tiles0/', 'tiles1/', 'tiles2/', 'tiles3/'];
var foodImgPaths=['food0/', 'food1/', 'food2/', 'food3/', 'food5/', 'food6/'];
var sprites;

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.hiscoredisplay=getElement('hiscoredisplay');
	elements.leveldisplay=getElement('leveldisplay');
	elements.labelLevel=getElement('labelLevel');
	elements.labelScore=getElement('labelScore');
	elements.mazedisplay=getElement('mazedisplay');
	elements.levelicons=getElement('levelicons');
	elements.livesicons=getElement('livesicons');
	elements.controls=getElement('controls');
	elements.maze=document.getElementById('maze');
	setVisibility(elements.controls, false);
	setVisibility(elements.maze, false);
	demomode=true;
	preload();
}

function preload() {
	imgRef=new Object();
	imgTotal=0;
	imgCnt=0;
	var i, k, p, dir, imgdir, imgs, ext, n, img, ts;
	for (dir in pacimages) {
		p=imgPath+dir+'/';
		imgdir=pacimages[dir];
		for (var k in imgdir) {
			imgs=imgdir[k];
			ext='.'+k;
			for (var i=0; i<imgs.length; i++) {
				n=imgs[i];
				img=imgRef[n]=new Image();
				img.src=p+n+ext;
				if (!img.complete) {
					imgTotal++;
					img.onload=preloadHandler;
				}
			}
		}
	}
	tileRef=new Array(tileImgPaths.length);
	for (k=0; k<tileImgPaths.length; k++) {
		ts = tileRef[k] = new Array();
		p=imgPath+tileImgPaths[k];
		for (i=0; i<tileimages.length; i++) {
			n=tileimages[i];
			img=ts[n]=new Image();
			img.src=p+n+'.png';
			if (!img.complete) {
				imgTotal++;
				img.onload=preloadHandler;
			}
		}
	}
	foodRef=new Array(foodImgPaths.length);
	for (k=0; k<foodImgPaths.length; k++) {
		ts = foodRef[k] = new Array();
		p=imgPath+foodImgPaths[k];
		for (i=0; i<foodimages.length; i++) {
			n=foodimages[i];
			img=ts[n]=new Image();
			img.src=p+n+'.png';
			if (!img.complete) {
				imgTotal++;
				img.onload=preloadHandler;
			}
		}
	}
	if (!imgTotal) 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';
	initAttractScreen();
	initMaze();
	initSprites();
	readPreferences();
	var select=getElement('mazeselect');
	select.selectedIndex=0;
	for (var i=0; i<select.options.length; i++) {
		if (select.options[i].value==mazeMode) {
			select.selectedIndex=i;
			break;
		}
	}
	setQuality(settingsQualityValue);
	setSpeed(settingsSpeedValue);
	setMazeMode(mazeMode);
	enableKeyboard();
	if (window.activateTouchControls) activateTouchControls();
	setTimeout('showAttractScreen()', 10);
}

function initMaze() {
	var r,c, imgsrc, i, id, x, y, z, mpr;
	var maze = elements.maze;
	var xpng=imgRef.x.src;
	var xgif= imgRef.xx.src;
	var misieFilter="progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+xpng+"', sizingMethod='crop')";
	for (r=0; r<22; r++) {
		mpr = mazePos[r+1] = new Array();
		for (c=0; c<19; c++) {
			x= (21-r)*14+c*24;
			y= 20+r*11+c*6;
			z= 2+c*6+r*114;
			mpr[c+1]= {x: x-2, y: y-10, z:z};
			id='t'+(r+1)+'_'+(c+1);
			i=document.createElement('img');
			i.id=id;
			if (msieLe6) {
				i.src=xgif;
				i.style.filter=misieFilter;
			}
			else {
				i.src=xpng;
			}
			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=imgRef.x.src;
	var xgif= imgRef.xx.src;
	if (msieLe6) {
		var misieFilter="progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+xpng+"', sizingMethod='crop')";
		for (i=1; i<=4; i++) {
			id='g'+i;
			d = elements[id]=document.createElement('div');
			d.style.visibility='hidden';
			d.style.position='absolute';
			
			id='gbody'+i;
			gd = elements[id]=document.createElement('div');
			gd.style.visibility='hidden';
			gd.style.position='absolute';
			gd.style.zIndex=1;
			id='igbody'+i;
			img=elements[id]=document.createElement('img');
			img.id=id;
			img.src=xgif;
			img.width=32; img.height=31;
			img.style.filter=misieFilter;
			gd.appendChild(img);
			d.appendChild(gd);
			
			id='geyes'+i;
			gd = elements[id]=document.createElement('div');
			gd.style.visibility='hidden';
			gd.style.position='absolute';
			gd.style.zIndex=2;
			id='igeyes'+i;
			img=elements[id]=document.createElement('img');
			img.id=id;
			img.src=xgif;
			img.width=32; img.height=31;
			img.style.filter=misieFilter;
			gd.appendChild(img);
			d.appendChild(gd);
			maze.appendChild(d);
			
			id='bonus'+i;
			gd = elements[id]=document.createElement('div');
			gd.style.visibility='hidden';
			gd.style.position='absolute';
			id='ibonus'+i;
			img=elements[id]=document.createElement('img');
			img.id=id;
			img.src=xgif;
			img.width=32; img.height=31;
			img.style.filter=misieFilter;
			gd.appendChild(img);
			maze.appendChild(gd);
		}
		d = elements.pac=document.createElement('div');
		d.id='pac';
		d.style.visibility='hidden';
		d.style.position='absolute';
		img = elements.ipac=document.createElement('img');
		img.id='ipac';
		img.src=xgif;
		img.width=36; img.height=35;
		img.style.filter=misieFilter;
		d.appendChild(img);
		maze.appendChild(d);
		d = elements.pac=document.createElement('div');
		d.id='fruit';
		d.style.visibility='hidden';
		d.style.position='absolute';
		img = elements.fruit=document.createElement('img');
		img.id='ifruit';
		img.src=xgif;
		img.width=32; img.height=31;
		img.style.filter=misieFilter;
		d.appendChild(img);
		maze.appendChild(d);
		d = elements.bonus5=document.createElement('div');
		d.id='bonus5';
		d.style.visibility='hidden';
		d.style.position='absolute';
		img = elements.ibonus5=document.createElement('img');
		img.id='ibonus5';
		img.src=xgif;
		img.width=32; img.height=31;
		img.style.filter=misieFilter;
		d.appendChild(img);
		maze.appendChild(d);
		sprites = {
			pac: {'div': elements.pac, 'img': elements.ipac},
			g: {
				'1': { 'div': elements.g1, 'body': elements.gbody1, 'eyes': elements.geyes1, 'bodyimg': elements.igbody1, 'eyesimg': elements.igeyes1 },
				'2': { 'div': elements.g2, 'body': elements.gbody2, 'eyes': elements.geyes2, 'bodyimg': elements.igbody2, 'eyesimg': elements.igeyes2 },
				'3': { 'div': elements.g3, 'body': elements.gbody3, 'eyes': elements.geyes3, 'bodyimg': elements.igbody3, 'eyesimg': elements.igeyes3 },
				'4': { 'div': elements.g4, 'body': elements.gbody4, 'eyes': elements.geyes4, 'bodyimg': elements.igbody4, 'eyesimg': elements.igeyes4 }
			},
			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},
				'5': {'div': elements.bonus5, 'img': elements.ibonus5}
			},
			fruit: {'div': elements.fruit, 'img': elements.ifruit}
		};
	}
	else {
		for (var i=1; i<=4; i++) {
			id='g'+i;
			var d = elements[id]=document.createElement('div');
			d.style.visibility='hidden';
			d.style.position='absolute';
			
			id='gbody'+i;
			img=elements[id]=document.createElement('img');
			img.id=id;
			img.src=xpng;
			img.width=32; img.height=31;
			img.style.position='absolute';
			img.style.display='block';
			img.style.zIndex=1;
			d.appendChild(img);
			
			id='geyes'+i;
			img=elements[id]=document.createElement('img');
			img.id=id;
			img.src=xpng;
			img.width=32; img.height=31;
			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=32; img.height=31;
			img.style.visibility='hidden';
			img.style.position='absolute';
			img.style.display='block';
			maze.appendChild(img);
		}
		img = elements.pac=elements.ipac=document.createElement('img');
		img.id='pac';
		img.src=xpng;
		img.width=36; img.height=35;
		img.style.visibility='hidden';
		img.style.position='absolute';
		img.style.display='block';
		maze.appendChild(img);
		img = elements.fruit=elements.ifruit=document.createElement('img');
		img.id='fruit';
		img.src=xpng;
		img.width=32; img.height=31;
		img.style.visibility='hidden';
		img.style.position='absolute';
		img.style.display='block';
		maze.appendChild(img);
		img = elements.bonus5=document.createElement('img');
		img.id='bonus5';
		img.src=xpng;
		img.width=32; img.height=31;
		img.style.visibility='hidden';
		img.style.position='absolute';
		img.style.display='block';
		maze.appendChild(img);
		sprites = {
			pac: {'div': elements.pac, 'img': elements.pac},
			g: {
				'1': { 'div': elements.g1, 'body': elements.gbody1, 'eyes': elements.geyes1, 'bodyimg': elements.gbody1, 'eyesimg': elements.geyes1 },
				'2': { 'div': elements.g2, 'body': elements.gbody2, 'eyes': elements.geyes2, 'bodyimg': elements.gbody2, 'eyesimg': elements.geyes2 },
				'3': { 'div': elements.g3, 'body': elements.gbody3, 'eyes': elements.geyes3, 'bodyimg': elements.gbody3, 'eyesimg': elements.geyes3 },
				'4': { 'div': elements.g4, 'body': elements.gbody4, 'eyes': elements.geyes4, 'bodyimg': elements.gbody4, 'eyesimg': elements.geyes4 }
			},
			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},
				'5': {'div': elements.bonus5, 'img': elements.bonus5}
			},
			fruit: {'div': elements.fruit, 'img': elements.fruit}
		};
	}
	
	d=elements.gameover=document.createElement('div');
	d.style.visibility='hidden';
	d.style.position='absolute';
	d.style.left='306px';
	d.style.top='198px';
	d.style.zIndex=1;
	img=document.createElement('img');
	img.src=imgRef.gameover.src;
	d.appendChild(img);
	maze.appendChild(d);
	d=elements.gamepaused=document.createElement('div');
	d.style.visibility='hidden';
	d.style.position='absolute';
	d.style.left='295px';
	d.style.top='196px';
	d.style.zIndex=1;
	img=document.createElement('img');
	img.src=imgRef.gamepaused.src;
	d.appendChild(img);
	maze.appendChild(d);
	d=elements.ready=document.createElement('div');
	d.style.visibility='hidden';
	d.style.position='absolute';
	d.style.left='326px';
	d.style.top='203px';
	d.style.zIndex=1;
	img=document.createElement('img');
	img.src=imgRef.ready.src;
	d.appendChild(img);
	maze.appendChild(d);
	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');
}

function initAttractScreen() {
	var maze=elements.maze;
	var xgif= imgRef.xx.src;
	var x=0;
	var y=150;
	var i;
	var d=elements.attractScreen=document.createElement('div');
	d.style.visibility='hidden';
	d.style.position='absolute';
	d.style.display='block';
	d.style.left=attractSrceenLeft+'px';
	d.style.top=attractScreenTop+'px';
	for (i=0; i<34; i++) {
		var img=elements['al'+i]=getAttractLight(i,x,y);
		d.appendChild(img);
		x+=9;
		y+=2;
	}
	for (i=34; i<48; i++) {
		var img=elements['al'+i]=getAttractLight(i,x,y);
		d.appendChild(img);
		y-=10;
	}
	for (i=48; i<82; i++) {
		var img=elements['al'+i]=getAttractLight(i,x,y);
		d.appendChild(img);
		x-=9;
		y-=2;
	}
	for (i=82; i<96; i++) {
		var img=elements['al'+i]=getAttractLight(i,x,y);
		d.appendChild(img);
		y+=10;
	}
	img=elements.attrCopyStatment=document.createElement('img');
	img.src=imgRef.attr_copystatement.src;
	img.style.visibility='hidden';
	img.style.position='absolute';
	img.style.display='block';
	img.style.left='36px';
	img.style.top='264px';
	d.appendChild(img);
	img=elements.attrWith=document.createElement('img');
	img.src=imgRef.attr_with.src;
	img.style.visibility='hidden';
	img.style.position='absolute';
	img.style.display='block';
	img.style.left='132px';
	img.style.top='70px';
	d.appendChild(img);
	img=elements.attrStarring=document.createElement('img');
	img.src=imgRef.attr_starring.src;
	img.style.visibility='hidden';
	img.style.position='absolute';
	img.style.display='block';
	img.style.left='117px';
	img.style.top='67px';
	d.appendChild(img);
	img=elements.attrMsPac=document.createElement('img');
	img.src=imgRef.attr_mspacman.src;
	img.style.visibility='hidden';
	img.style.position='absolute';
	img.style.display='block';
	img.style.left='103px';
	img.style.top='125px';
	d.appendChild(img);
	for (var i=1; i<=4; i++) {
		img=elements['attrG'+i]=document.createElement('img');
		img.src=imgRef['attr_g'+i].src;
		img.style.visibility='hidden';
		img.style.position='absolute';
		img.style.display='block';
		img.style.left='125px';
		img.style.top='130px';
		d.appendChild(img);
	}
	maze.appendChild(d);
}

function getAttractLight(i,x,y) {
	var img=elements['al'+i]=document.createElement('img');
	img.src=imgRef.xx.src;
	img.width=7; img.height=8;
	img.style.visibility='hidden';
	img.style.position='absolute';
	img.style.display='block';
	img.style.left=x+'px';
	img.style.top=y+'px';
	return img;
}

// definitions

var settingsQuality=new Array(5, 6, 7);
//var settingsSpeed=new Array(258, 235, 212, 190);
var settingsSpeed=new Array(238, 222, 206, 180);
var settingsPillBlinkDelay=new Array(8,9,11,13);
var settingsQualityValue=1;
var settingsSpeedValue=1;
var aStep=6;
var aSpeed=252;
var gameDelay;

var blinkRate=4;
var blinkSteps=6;
var pillFactor=1.75;
var pillMaxLength=26;
var pillMinLength=10;
var eyesFactor=.75;
var bonusLifeScore=10000;
var useInstantTurns=true;
var allwaysStartInScatterMode=true;
var fruitFactorMsP1 = 0.286;
var fruitFactorMsP2 = 0.705;
var useFruitSideEnter = true;
var fruitMoving=true;
var pillBlinkDelay=9;
var bonusLength;
var pacseed=0;
var mazeMode='MsPacman';
var hiScores = new Object();
var hiScore=0;

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

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

var highscore=0;

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

var msPacLevels = [
{
name: "Remember Ms. Pac-Man? &ndash; Part  1",
tileClr: 0,
foodClr: 0,
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",
scatterPos: [[0,0], [4,2], [22,17], [22,2], [4,17]],
tileClr: 1,
foodClr: 1,
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",
tileClr: 2,
foodClr: 2,
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",
tileClr: 3,
foodClr: 5,
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 ghostsLevels= [
{
name: 'Meeting Blinky',
tileClr: 0,
foodClr: 0,
maze: [
	'ahhhhhhhhihhhhhhhhc',
	'v........v........v',
	'v.n.ahhc.o.ahhc.n.v',
	'vpv.bhhd...bhhd.vpv',
	'v.v......n......v.v',
	'v.bm.n.lhfhm.n.ld.v',
	'v....v.......v....v',
	'bhhc.emxlhmxlg.ahhd',
	'xxxv.vxxxxxxxv.vxxx',
	'lhhd.oxautwcxo.bhhm',
	'XXXX.xxvxxxvxx.XXXX',
	'lhhc.nxbhhhdxn.ahhm',
	'xxxv.vxxxxxxxv.vxxx',
	'ahhd.emxlimxlg.bhhc',
	'v....v...v...v....v',
	'v.lm.o.n.o.n.o.lm.v',
	'v......v.x.v......v',
	'v.am.n.bhhhd.n.lc.v',
	'vpv..v.......v..vpv',
	'v.o.lfhm.n.lhfm.o.v',
	'v........v........v',
	'bhhhhhhhhfhhhhhhhhd'
]
},
{
name: 'Meeting Pinky',
tileClr: 1,
foodClr: 3,
maze: [
	'ahhhhhhhhhhhhhhhhhc',
	'v.................v',
	'vpac.n.ahhhc.n.acpv',
	'v.bd.o.o...o.o.bd.v',
	'v........n........v',
	'bc.ahm.lhyhm.lhc.ad',
	'xv.v.....v.....v.vx',
	'ld.o.ahmxoxlhc.o.bm',
	'XX...oxxxxxxxo...XX',
	'lc.nxxxautwcxxxn.am',
	'xv.ehmxvxxxvxlhg.vx',
	'ld.oxxxbhhhdxxxo.bm',
	'XX...nxxxxxxxn...XX',
	'lc.n.bhmxnxlhd.n.am',
	'xv.v...xxvxx...v.vx',
	'ad.bhm.lhfhm.lhd.bc',
	'v........x........v',
	'v.am.n.lhihm.n.lc.v',
	'vpv..v...v...v..vpv',
	'v.o.lfhm.o.lhfm.o.v',
	'v.................v',
	'bhhhhhhhhhhhhhhhhhd'
]
},
{
name: 'Meeting Sue (Clyde)',
tileClr: 2,
foodClr: 0,
maze: [
	'ahhhhhihhhhhihhhhhc',
	'v.....v.....v.....v',
	'vplhm.o.ahc.o.lhmpv',
	'v.......bhd.......v',
	'v.n.n.n.....n.n.n.v',
	'v.o.o.bhm.lhd.o.o.v',
	'v.................v',
	'bhhc.kxlhhhmxk.ahhd',
	'xxxv.xxxxxxxxx.vxxx',
	'lhhd.nxautwcxn.bhhm',
	'XXXX.vxvxxxvxv.XXXX',
	'lhhc.oxbhhhdxo.ahhm',
	'xxxv.xxxxxxxxx.vxxx',
	'ahhd.kxlhhhmxk.bhhc',
	'v.................v',
	'v.lhm.lhc.ahm.lhm.v',
	'v.......vxv.......v',
	'v.ahc.n.o.o.n.ahc.v',
	'vpvxv.v.....v.vxvpv',
	'v.bhd.bhm.lhd.bhd.v',
	'v.................v',
	'bhhhhhhhhhhhhhhhhhd'
]
},
{
name: 'Meeting Inky',
tileClr: 3,
foodClr: 3,
maze: [
	'ahhhhhhhhhhhhhhhhhc',
	'v.................v',
	'o.lhc.ahhhhhc.ahm.o',
	'X..po.o.....o.op..X',
	'n.n.....ahc.....n.n',
	'v.bm.lm.bhd.lm.ld.v',
	'v.................v',
	'bc.lhcxlhhhmxahm.ad',
	'xv...oxxxxxxxo...vx',
	'xv.n.xxautwcxx.n.vx',
	'xv.bhmxvxxxvxlhd.vx',
	'xv.xxxxbhhhdxxxx.vx',
	'xv.ahmxxxxxxxlhc.vx',
	'xv.o...lhihm...o.vx',
	'xv...n...v...n...vx',
	'ad.lhfhm.o.lhfhm.bc',
	'vp.......x.......pv',
	'o.am.n.lhihm.n.lc.o',
	'X.v..v...v...v..v.X',
	'n.o.lfhm.o.lhfm.o.n',
	'v.................v',
	'bhhhhhhhhhhhhhhhhhd'
]
}
];

var msPacPlusLevels = [
{
name: "Ms. Pac-Man Plus, Part 1",
tileClr: 0,
foodClr: 0,
maze: [
	'xxxxxxahhhhhcxxxxxx',
	'ahhhhhd.....bhhhhhc',
	'vp......ahc......pv',
	'v.n.ac.afhfc.ac.n.v',
	'v.o.bd.o...o.bd.o.v',
	'v........n........v',
	'vxahhmxahfhcxlhhcxv',
	'vxv..xxbhhhdxx..vxv',
	'vxv.lmxxxxxxxlm.vxv',
	'vxv..xxautwcxx..vxv',
	'oxbhicxvxxxvxaihdxo',
	'Xx..bdxbhhhdxbd..xX',
	'nxn...xxxxxxx...nxn',
	'vxbhm.ac.z.ac.lhdxv',
	'v.....bg...ed.....v',
	'v.lhc..bhhhd..ahm.v',
	'v...bm...x...ld...v',
	'v.n....ahhhc....n.v',
	'v.bhic.v...v.aihd.v',
	'vp..bd.o.n.o.bd..pv',
	'bhc......v......ahd',
	'xxbhhhhhhfhhhhhhdxx'
]
},
{
name: "Ms. Pac-Man Plus, Part 2",
tileClr: 1,
foodClr: 1,
maze: [
	'ahhhhhhihhhihhhhhhc',
	'v......v...v......v',
	'v.lhhm.v.n.v.lhhm.v',
	'vp.....v.v.v.....pv',
	'bhhm.n.v.v.v.n.lhhd',
	'XXXX.v.o.v.o.v.XXXX',
	'ahhm.v...v...v.lhhc',
	'v....ehmxoxlhg....v',
	'v.ac.vxxxxxxxv.ac.v',
	'v.vv.vxautwcxv.vv.v',
	'v.vv.vxvxxxvxv.vv.v',
	'v.bd.oxbhhhdxo.bd.v',
	'v....xxxxxxxxx....v',
	'bhm.ahhmxnxlhhc.lhd',
	'XXX.v...xvx...v.XXX',
	'ahm.v.lhhfhhm.v.lhc',
	'v...v....x....v...v',
	'v.n.ehhm.n.lhhg.n.v',
	'vpv.v....v....v.vpv',
	'v.o.o.lm.v.lm.o.o.v',
	'v........v........v',
	'bhhhhhhhhfhhhhhhhhd'
]
},
{
name: "Ms. Pac-Man Plus, Part 3",
tileClr: 2,
foodClr: 2,
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',
	'ec.lhgxlhfhmxehm.ag',
	'vv...vxxxxxxxv...vv',
	'vvXn.oxautwcxo.vXvv',
	'bdXv.xxvxxxvxx.vXbd',
	'XXXv.nxbhhhdxn.vXXX',
	'aihd.vxxxxxxxv.bhic',
	'vv...bhmxnxlhd...vv',
	'vv.n...xxvxx...n.vv',
	'ed.bhm.lhfhm.lhd.bg',
	'v......xxxxx......v',
	'v.am.n.lhhhm.n.lc.v',
	'vpv..v.......v..vpv',
	'v.o.lfhm.n.lhfm.o.v',
	'v........v........v',
	'bhhhhhhhhfhhhhhhhhd'
]
},
{
name: "Ms. Pac-Man Plus, Part 4",
tileClr: 3,
foodClr: 5,
maze: [
	'ahhhhhhhhihhhhhhhhc',
	'v........v........v',
	'vplhm.lm.v.lm.lhmpv',
	'v........o........v',
	'v.lhm.lm...lm.lhm.v',
	'v........n........v',
	'v.acxnxahfhcxnxac.v',
	'o.bdxoxbhhhdxoxbd.o',
	'X...xxxxxxxxxxx...X',
	'ahm.lmxautwcxlm.lhc',
	'v...xxxvxxxvxxx...v',
	'v.acxnxbhhhdxnxac.v',
	'v.vvxvxxxxxxxvxvv.v',
	'o.bdxoxlhhhmxoxbd.o',
	'X.....xxxxxxx.....X',
	'ahhhm.nxlhmxn.lhhhc',
	'vp....oxxxxxo....pv',
	'v.n.n...lhm...n.n.v',
	'v.v.v.n..x..n.v.v.v',
	'v.o.o.bm.n.ld.o.o.v',
	'v........v........v',
	'bhhhhhhhhfhhhhhhhhd'
]
}
];

var colorCombos = [
	[0,2,4],
	[0,1,2,3],
	[0,2,3,4],
	[5,1,2,3]
];

var levels, allLevels, msPacAttackLevels, tileset, foodset, tileColor;

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 tpf = [4,2,8,1,1,2,4,8,8,4,1,2,2,4,1,8,4,2,8,1,1,2,4,1,8,2,8,4,2,4,1,8,
			4,2,8,1,1,2,4,1,8,2,8,4,2,4,1,8,4,2,8,1,1,2,4,1,8,2,8,4,2,4,1,8];
var tpd = {
	4: 0,
	2: 1,
	8: 2,
	1: 3
};

var demoPath= [2,8,2,8,2,2,4,1,4,4,1,4,1,4,4,2,4,1,1,8,2,2,4,4,2,8,1];
var demomode, demoCnt, demoUsedSound, demoCntMax;

var mazePos = new Array();

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

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 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;
var phaseSet=true;
var bonusLifeCnt=0;
var pacInitDir=0;
var ghostInitDir=0;
var pillPeriode, pillCnt;
var isPause=false;
var restartDialogOn=false;
var gameTimer=null, demoTimer=null;
var enterTime=0;
var scatterMode, stepCnt, scatterCnt, moved, gLeaveLeft;

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

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

var pacStr= {
	'0': ['mpl1', 'mpl1', 'mpl1'],
	'1': ['mpr1', 'mpr2', 'mpr3'],
	'2': ['mpl1', 'mpl2', 'mpl3'],
	'4': ['mpb1', 'mpb1', 'mpb1'],
	'8': ['mpf1', 'mpf2', 'mpf3'],
	'x': ['mpx1', 'mpx2', 'mpx3', 'mpx4', 'mpx5', 'mpx6', 'mpx7', 'mpx8']
};

var ghostStr= {
	'1': ['g11', 'g12', 'g13'],
	'2': ['g21', 'g22', 'g23'],
	'3': ['g31', 'g32', 'g33'],
	'4': ['g41', 'g42', 'g43'],
	'a': ['ga1', 'ga2', 'ga3'],
	'n': ['gn1', 'gn2', 'gn3']
};

var eyeRef= {
	'normal': { '0': 'e0', '1': 'e1', '2': 'e2', '4': 'x', '8': 'e0' },
	'pill': { '0': 'ea0', '1': 'ea1', '2': 'ea2', '4': 'x', '8': 'ea0' },
	'homebound': { '0': 'ea0', '1': 'eh1', '2': 'eh2', '4': 'eh4', '8': 'eh8' },
	'home': { '0': 'ex0', '1': 'ex1', '2': 'ex2', '4': 'ex4', '8': 'ex8' }
};
var fruitRef = ['f1', 'f2', 'f3', 'f7', 'f8', 'f9', 'f10'];
var fruitBonusRef=['bonus4', 'bonus10', 'bonus6', 'bonus7', 'bonus8', 'bonus11', 'bonus12'];
var fruitBonusVal=[100, 200, 500, 700, 1000, 2000, 5000];
var fruit, fruitImg, fruitCnt, fruitLimit, fruitLimits, fruitPorts, fruitBonus, fruiticons;

var scatterPhase;
var scatterSet= [
	[
		[0, 33],
		[94, 33],
		[94, 24],
		[94, 24],
		[10000, 2]
	],
	[
		[0, 33],
		[100, 33],
		[100, 24],
		[4870, 2],
		[10000, 2]
	],
	[
		[0, 24],
		[98, 24],
		[98, 24],
		[4889, 2],
		[10000, 2]
	]
];

var pillPhases = [0,28,24,19,14,9,24,9,9,5,24,9,5,5,14,5,5,0,5];

var pacOffsetY=5;
var trueMspacmode, pillPos, pillsVisible, pillBlinkCnt;
var scatterPhaseCnt, mspacScatterOffset, mspacScatterPos;

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

var nextGhost, foodTimer,useGlobalHomeCnt,maxFoodDelay;
var globalHomeCnt=0;
var ghostPenCounts = [0,5,11,21,0];

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

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.z= 0;
	this.osx=0;
	this.osy=0;
	this.posx=0;
	this.posy=0;
	this.bid=0;
	this.bm=0;
	this.alpha=1;
	this.e=-1;
	this.pill=false;
	this.scatter=false;
	this.scnt=0;
	this.tunnel=false;
	this.reverse=false;
	this.step=0;
	this.turn=0;
	this.homeCnt=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='';
}


// 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) {
				var f=obj.filters.item('DXImageTransform.Microsoft.Alpha');
				f.opacity = Math.floor(v*100);
				f.enabled = true;
			}
			else {
				obj.filters.item('DXImageTransform.Microsoft.Alpha').enabled = false;
			}
		}
	}
	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) {
	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) {
	var tile=elements['t'+r+'_'+c];
	switch (s) {
		case 'x': tile.src=imgRef.x.src; break;
		case 'p':
		case 'pnt': tile.src=foodset[s].src; break;
		default: tile.src=tileset[s].src;
	}
}

// msie-pre-7 png fixes

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

function setMazeMsieLe6(r,c,s) {
	var f=elements['t'+r+'_'+c].filters;
	switch (s) {
		case 'x': f.item(0).src=imgRef.x.src; break;
		case 'p':
		case 'pnt':f.item(0).src=foodset[s].src; break;
		default: f.item(0).src=tileset[s].src;
	}
}


// settings

function setQuality(v) {
	var s1=aStep;
	var s2=gStep;
	var s3=gStep2;
	aStep=settingsQuality[v];
	setSpan();
	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;
	if (cf1>1 || Math.abs(pac.osx)>1) pac.osx=Math.round(pac.osx*cf1);
	if (cf1>1 || Math.abs(pac.osy)>1) pac.osy=Math.round(pac.osy*cf1);
	limitOffsets(pac, aStep);
	for (var i=1; i<=4; i++) {
		var gi=g[i];
		if (gi.osx+gi.osy==0) continue;
		if (gi.s==0 || (gi.s==2 && (gi.pill || gi.tunnel))) {
			if (cf2>1 || Math.abs(gi.osx)>1) gi.osx=Math.round(gi.osx*cf2);
			if (cf2>1 || Math.abs(gi.osy)>1) gi.osy=Math.round(gi.osy*cf2);
			limitOffsets(gi, gStep);
		}
		else if (gi.s==3) {
			if (cf3>1 || Math.abs(gi.osx)>1) gi.osx=Math.round(gi.osx*cf3);
			if (cf3>1 || Math.abs(gi.osy)>1) gi.osy=Math.round(gi.osy*cf3);
			limitOffsets(gi, gStep2);
		}
		else {
			if (cf1>1 || Math.abs(gi.osx)>1) gi.osx=Math.round(gi.osx*cf1);
			if (cf1>1 || Math.abs(gi.osy)>1) gi.osy=Math.round(gi.osy*cf1);
			limitOffsets(gi, aStep);
		}
	}
	if (fruit) {
		if (cf2>1 || Math.abs(fruit.osx)>1) fruit.osx=Math.round(fruit.osx*cf2);
		if (cf2>1 || Math.abs(fruit.osy)>1) fruit.osy=Math.round(fruit.osy*cf2);
		limitOffsets(fruit, gStep);
	}
	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);
	pillBlinkDelay=settingsPillBlinkDelay[settingsSpeedValue];
}

function setMazeMode(v) {
	mazeMode=v;
	hiScore=hiScores[mazeMode];
	var v=(hiScore)? hiScore:'00';
	elements.hiscoredisplay.innerHTML=v;
	nScore=0;
	if (!demomode) newGame();
}

// maze & game setup

function buildMaze(lvl) {
	var r, c, d, f1r, fwr, z, m;
	if (!demomode) {
		if (lvl.name) {
			displayMazeName(lvl.name);
		}
		else {
			displayMazeName('');
		}
	}
	if (lvl.scatterPos) {
		scatterPos=lvl.scatterPos;
	}
	else {
		scatterPos=scatterPos2;
	}
	mspacScatterPos = [ scatterPos[3], scatterPos[1], scatterPos[2], scatterPos[4] ];
	pillPos=new Array();
	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 if (z=='X') {
				setMaze(r,c,"x");
				f1r[c]=-1;
				fwr[c]=true;
			}
			else {
				setMaze(r,c,z);
				if (z=='p') {
					f1r[c]=8;
					food++;
					pillPos.push([r,c,true]);
				}
				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
	if (lvl.mazedirs) {
		f2=lvl.mazedirs;
	}
	else {
		f2=new Array(23);
		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];
		}
		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;
				}
			}
		}
		lvl.mazedirs=f2;
	}
	
	if (lvl.homepaths) {
		fgh=lvl.homepaths;
		fruitPorts = lvl.fruitports;
	}
	else {
		fruitPorts=new Array();
		fgh=lvl.homepaths=getHomePaths();
		lvl.fruitports=fruitPorts;
	}
}

function getHomePaths() {
	var i, d, d2, d3, r, c, p, n;
	var f = new Array(23);
	for (r=1; r<=22; r++) {
		f[r]=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];
	}
	var paths=new Array();
	var a=t2[ghostInitDir];
	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;
				fruitPorts.push(r);
			}
			else if (c>19) {
				c=1;
			}
			if (!f[r][c]) {
				d2=f2[r][c];
				d3=t3[d];
				f[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;
	}
	return f;
}


// attract screen

var attractSrceenLeft=210;
var attractScreenTop=36;
var attractStartX=attractSrceenLeft-50;
var attractStartY=attractScreenTop+177;
var attractBottomY=attractScreenTop+260;
var attractGhost;

function showAttractScreen() {
	if (gameTimer) clearTimeout(gameTimer);
	if (demoTimer) clearTimeout(demoTimer);
	gameTimer=demoTimer=0;
	demomode=true;
	setVisibility(elements.maze, false);
	setRestartDialogVisible(false);
	setVisibility(elements.gameover, false);
	setVisibility(elements.gamepaused, false);
	setVisibility(elements.ready, false);
	setVisibility(elements.maze, true);
	setVisibility(elements.attrWith,false);
	setVisibility(elements.attrStarring,false);
	setVisibility(elements.attrMsPac,false);
	for (var i=1; i<=4; i++) setVisibility(elements['attrG'+i],false);
	setVisibility(elements.attractScreen, true);
	setVisibility(elements.attrCopyStatment, true);
	elements.attractScreen.style.display='block';
	showControls(false);
	var i;
	setVisibility(sprites.pac.div, false);
	setVisibility(sprites.fruit.div, false);
	setMazeVisibility(false);
	for (i=1; i<=5; i++) {
		if (i<5) setVisibility(sprites.g[i].div, false);
		setVisibility(sprites.bonus[i].div, false);
	}
	for (i=0; i<96; i++) {
		var img=elements['al'+i];
		img.src=imgRef.xx.src;
		setVisibility(img, true);
	}
	stepCnt=0;
	pillBlinkCnt=0;
	gameStatus=0;
	elements.mazedisplay.innerHTML='&ndash; Push button or type &quot;N&quot; to start a new game. &ndash;';
	setVisibility(elements.maze, true);
	setVisibility(elements.controls, true);
	gameTimer=setTimeout('attractStep()', 20);
}

function setMazeVisibility(v) {
	var vis=(v)? 'visible':'hidden';
	var hide=(v)? false:true;
	for (var r=1; r<=22; r++) {
		for (var c=1; c<=19; c++) {
			var t=elements['t'+r+'_'+c];
			t.style.visibility=vis;
			if (hide) t.src=imgRef.x.src;
		}
	}
}

function attractStep() {
	var now=new Date();
	enterTime=now.getTime();
	var img;
	switch (gameStatus) {
		case 0:
			showAttractGhost(4);
			pillBlinkCnt=0;
			phaseSet=false;
			gameStatus=2;
			break;
		case 1:
			img=elements['al'+pillBlinkCnt];
			img.src=imgRef.attr_light0.src;
			if (++pillBlinkCnt==96) {
				pillBlinkCnt=0;
				phaseSet=true;
				gameStatus++;
				setVisibility(elements.attrG4,true);
				setSpriteImg(sprites.g[attractGhost].eyesimg, eyeRef.normal[1]);
			}
			if (pillBlinkCnt==64) {
				setVisibility(elements.attrWith,true);
			}
			break;
		case 2:
			if (phaseSet) {
				for (var i=0; i<6; i++) {
					var n=(pillBlinkCnt+i*16)%96;
					img=elements['al'+n];
					img.src=imgRef.attr_light1.src;
					n--;
					if (n<0) n+=96;
					img=elements['al'+n];
					img.src=imgRef.attr_light0.src;
				}
				pillBlinkCnt=(pillBlinkCnt+1)%96;
			}
			if (attractGhost==0) {
				stepCnt++;
				if (stepCnt%3==0) {
					pac.p+=pac.pn;
					if (pac.p==0) {
						pac.pn=1;
					}
					else if (pac.p==2) {
						pac.pn=-1;
					}
					setSpriteImg(sprites.pac.img, pacStr[1][pac.p]);
				}
				sprites.pac.div.style.left=(attractStartX+Math.round(stepCnt*9/3))+'px';
				sprites.pac.div.style.top=(attractStartY+Math.round(stepCnt*2/3))+'px';
				if (stepCnt==63) {
					attractGhost=-1;
					setSpriteImg(sprites.pac.img, pacStr[1][2]);
				}
			}
			else if (attractGhost>0 && ++stepCnt<184-(attractGhost%4)*12) {
				var gi=g[attractGhost];
				var gs=sprites.g[attractGhost];
				if (stepCnt==125) {
					setSpriteImg(gs.eyesimg, eyeRef.home[4]);
					gi.d=4;
				}
				if (gi.d==1) {
					gs.div.style.left=(attractStartX+Math.round(stepCnt*9/3))+'px';
					gs.div.style.top=(attractStartY+Math.round(stepCnt*2/3))+'px';
				}
				else {
					gs.div.style.top=(attractBottomY-(stepCnt-125)*3)+'px';
				}
				if (stepCnt%4==0) {
					gi.p=(gi.p+1)%3;
					setSpriteImg(gs.bodyimg, ghostStr[attractGhost][gi.p]);
				}
				if (!phaseSet && stepCnt==26) {
					setSpriteImg(gs.eyesimg, eyeRef.homebound[2]);
					demoCnt=0;
					gameStatus=3;
				}
			}
			else if (attractGhost<0 && ++stepCnt>=250) {
				gameTimer=setTimeout('startDemo()',19);
				return;
			}
			else {
				if (attractGhost>0) {
					if (attractGhost==4) setVisibility(elements.attrWith, false);
					setVisibility(elements['attrG'+attractGhost], false);
					if (attractGhost==3) {
						setVisibility(elements.attrStarring, true);
						setVisibility(elements.attrMsPac, true);
						setSpriteImg(sprites.pac.img, pacStr[1][0]);
						sprites.pac.div.style.left=attractStartX+'px';
						sprites.pac.div.style.top=attractStartY+'px';
						setOpacity(sprites.pac.div, 1);
						setVisibility(sprites.pac.div, true);
						pac.p=0;
						pac.pn=1;
						attractGhost=0;
						stepCnt=0;
					}
					else {
						showAttractGhost((attractGhost==4)? 1: attractGhost+1);
						setVisibility(elements['attrG'+attractGhost], true);
					}
				}
			}
			break;
		case 3:
			demoCnt++;
			var gs=sprites.g[4];
			switch (demoCnt) {
				case 25:
					setSpriteImg(gs.eyesimg, eyeRef.homebound[1]); break;
				case 50:
					setSpriteImg(gs.eyesimg, eyeRef.home[4]); break;
				case 75: gameStatus=1; break;
			}
			break;
	}
	gameTimer=setTimeout('attractReLoop()', 1);
}

function attractReLoop() {
	if (gameTimer) clearTimeout(gameTimer);
	var now=new Date();
	var delay = ((gameStatus==1)? 21:19) + enterTime - now.getTime();
	gameTimer=setTimeout('attractStep()', (delay>0)? delay:1);
}

function showAttractGhost(i) {
	attractGhost=i;
	var gi=g[i];
	gi.p=0;
	gi.d=1;
	var gs=sprites.g[i];
	setOpacity(gs.body, 1);
	setOpacity(gs.eyes, 1);
	setSpriteImg(gs.bodyimg, ghostStr[i][0]);
	setSpriteImg(gs.eyesimg, eyeRef.normal[1]);
	gs.div.style.left=attractStartX+'px';
	gs.div.style.top=attractStartY+'px';
	setVisibility(gs.div, true);
	stepCnt=0;
}

function startDemo() {
	demoUsedSound=useSound;
	useSound=false;
	demoCnt=0;
	if (mazeMode!='MsPacman') {
		demoCntMax=1;
	}
	else if (pacseed==0) {
		demoCntMax=demoPath.length;
		pacseed=12;
	}
	else {
		demoCntMax=4;
	}
	newGame(true);
	showControls(false);
	setOpacity(elements.gameover, 1);
}

function endDemo() {
	demomode=false;
	useSound=demoUsedSound;
	gameTimer=setTimeout('showAttractScreen()', 1000);
}

function showControls(v) {
	setVisibility(elements.livesicons, v);
	setVisibility(elements.levelicons, v);
	setVisibility(elements.labelLevel, v);
	setVisibility(elements.leveldisplay, v);
	setVisibility(elements.labelScore, v);
	setVisibility(elements.scoredisplay, v);
}


// general

function pHome(initial, initscatter) {
	pill=false; pillCnt=0;
	movedir=0;
	with (pac) {
		r=17; c=10;
		osx=0; osy=0;
		md=0; dir= pacInitDir;
		dx=0; dy=0;
		pn=1; p=0;
		reversed=false;
		lc='';
	}
	if (initscatter) {
		stepCnt=0;
		scatterMode=true;
		if (!initial && scatterPhaseCnt==0) scatterPhaseCnt++;
		scatterCnt=scatterPhase[0][1];
		setupMspacScatter();
	}
	else if (moved) resetScatter();
	moved=false;
	dotsound1=true;
	setPac(pac.r,pac.c, pacStr[0][0]);
	setOpacity(sprites.pac.div, 1);
	if (fruit) hideFruit();
	if (bonus[5]) {
		setVisibility(sprites.bonus[5].div, false);
		bonus[5]=0;
	}
	setOpacity(sprites.fruit.div, 1);
	globalHomeCnt=0;
	if (demomode) {
		setVisibility(elements.gameover, true);
	}
	else {
		setVisibility(elements.ready, true);
	}
}

function gHome(i, initial) {
	with (g[i]) {
		var hp, ghid;
		if (i==4) {
			hp=(initial || nextGhost==1)? gHomePos[4]:gHomePos[1];
		}
		else {
			hp=gHomePos[i];
		}
		for (var k=i%4+1; k<4; k++) {
			if (g[k].s==0) reallocateGhost(k);
		}
		r=hp[0];
		c=hp[1];
		osx=osy=0;
		s=0; p=0;
		z=1;
		d=0;
		e=-1;
		pill=false;
		alpha=1;
		scatter=scatterMode;
		scnt=0;
		step=0;
		turn=0;
		tunnel=false;
		reverse=false;
		setGhost(i,r,c);
		fft[r][c]=bid;
	}
	var gs=sprites.g[i];
	setOpacity(gs.body, 1);
	setOpacity(gs.eyes, 1);
	setVisibility(gs.div, true);
	if (i==4 || nextGhost==0 || nextGhost%4>i) nextGhost=i;
}

function reallocateGhost(i) {
	with (g[i]) {
		turn=d=osx=osy=0;
		r=gHomePos[i][0];
		c=gHomePos[i][1];
		setGhost(i,r,c);
		fft[11][10]&=bm;
		fft[10][10]&=bm;
		fft[9][10]&=bm;
		fft[r][c]=bid;
	}
}

function resetHomeCnts() {
	for (var i=1; i<=4; i++) {
		if (i==2 && nLevel==1) {
			g[i].homeCnt=19;
		}
		else if (i==3 && nLevel<3) {
			g[i].homeCnt=(nLevel==1)? 38:32;
		}
		else {
			g[i].homeCnt=0;
		}
	}
}

function fHome() {
	with (fruit) {
		if (useFruitSideEnter) {
			posy=r=fruitPorts[Math.floor(Math.random()*fruitPorts.length)];
			if (Math.random()>=.5) {
				posx=c=1;
				d=1;
			}
			else {
				posx=c=19;
				d=2;
			}
		}
		else {
			posx=c=10;
			posy=r=13;
			d=(Math.random()>=.5)? 2:1;
		}
		osx=0;
		osy=0;
		s=1;
		p=0; pn=1;
	}
	setFruit();
	setVisibility(sprites.fruit.div, true);
	if (useSound) playSound('assetenter');
}

function newGame(isDemo) {
	if (gameTimer) clearTimeout(gameTimer);
	if (demoTimer) clearTimeout(demoTimer);
	demoTimer=0;
	isPause=false;
	setVisibility(elements.attractScreen, false);
	elements.attractScreen.style.display='none';
	setRestartDialogVisible(false);
	setVisibility(elements.gameover, false);
	setVisibility(elements.gamepaused, false);
	setVisibility(elements.ready, false);
	if (msie) {
		setVisibility(elements.maze,true);
	}
	else {
		setOpacity(elements.maze, 1);
	}
	if (demomode) {
		setMazeVisibility(true);
	}
	else {
		if (nScore && nScore==hiScore && hiScores[mazeMode]<nScore) {
			hiScores[mazeMode]=hiScore;
		}
	}
	demomode=(isDemo)? true:false;
	trueMspacmode=true;
	switch (mazeMode) {
		default:
		case 'MsPacman':
			levels=msPacLevels;
			break;
		case 'MsPacmanPlus':
			levels=msPacPlusLevels;
			break;
		case 'GhostsLevels':
			levels=ghostsLevels;
			break;
		case 'MsPacAttack': {
			if (!msPacAttackLevels) {
				msPacAttackLevels=new Array();
				msPacAttackLevels.push(msPacPlusLevels[1]);
				msPacAttackLevels.push(msPacPlusLevels[0]);
				msPacAttackLevels.push(msPacPlusLevels[2]);
				msPacAttackLevels.push(msPacPlusLevels[3]);
			}
			levels=msPacAttackLevels;
			break;
		}
		case 'Shuffle':
			if (!allLevels) allLevels=msPacLevels.concat(msPacPlusLevels, ghostsLevels);
			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] );
			trueMspacmode=false;
			break;
	}
	nLife=3;
	setImage('life1','mlife');
	setImage('life2','mlife');
	setImage('life3','xx');
	setImage('life4','xx');
	setImage('life5','xx');
	nScore=0;
	nLevel=0;
	displayLevel();
	displayScore();
	bonusLifeCnt=0;
	fruitCnt=-1;
	fruiticons=new Array();
	showControls(true);
	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.bonus[5].div, false);
	setVisibility(sprites.fruit.div, false);
	bonus[5]=0;
	runThru=false;
	nLevel++;
	displayLevel();
	displayScore();
	gameStatus=0;
	statusCnt=0;
	switch (nLevel) {
		case 1:
			scatterPhase=scatterSet[0];
			break;
		case 2:
		case 3:
		case 4:
			scatterPhase=scatterSet[1];
			break;
		default:
			scatterPhase=scatterSet[2];
			break;
	}
	pillPeriode = (nLevel<pillPhases.length)? pillPhases[nLevel]:0;
	var tc, lvl,cc;
	setVisibility(elements.maze, false);
	if (trueMspacmode) {
		var lvl;
		if (nLevel<9) {
			lvl =  levels[Math.floor((nLevel-1)/2)];
			tileColor=lvl.tileClr;
			tileset = tileRef[tileColor];
			foodset = foodRef[lvl.foodClr];
		}
		else {
			lvl =  levels[2+Math.floor(((nLevel-1)%4)/2)];
			if (nLevel%2) {
				tc=getRand(tileRef.length);
				while(tc==tileColor) tc=getRand(tileRef.length);
				tileColor=tc;
				tileset = tileRef[tileColor];
				cc=colorCombos[tileColor];
				foodset = foodRef[cc[getRand(cc.length)]];
			}
		}
		buildMaze(lvl);
	}
	else {
		tc=getRand(4);
		while(tc==tileColor) tc=getRand(tileRef.length);
		tileColor=tc;
		tileset=tileRef[tileColor];
		cc=colorCombos[tileColor];
		foodset = foodRef[cc[getRand(cc.length)]];
		buildMaze(levels[(nLevel-1)%levels.length]);
	}
	for (var r=1; r<=22; r++) {
		for (var c=1; c<=19; c++) {
			fft[r][c]=0;
		}
	}
	setVisibility(elements.maze, true);
	
	fruitCnt++;
	var fimg;
	fruitBonus = (fruitCnt<7)? fruitCnt:Math.floor(Math.random()*7);
	fimg = fruitRef[fruitBonus];
	fruitLimits =[ food-Math.round(food*fruitFactorMsP1), food-Math.round(food*fruitFactorMsP2) ];
	if (nLevel<=7) setLevelIcon(fimg);
	setSpriteImg(sprites.fruit.img, fimg);
	fruitLimit = fruitLimits[0];
	fruit=null;
	
	gLeaveLeft=true;
	scatterPhaseCnt=0;
	phaseSet=true;
	pHome(true, true);
	for (var i=1; i<=4; i++) gHome(i, true);
	resetHomeCnts();
	useGlobalHomeCnt=false;
	maxFoodDelay = (nLevel==1)? 4000:3000;
	setVisibility(sprites.pac.div, true);
	pillBlinkCnt=pillBlinkDelay;
	pillsVisible=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;
	
	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) };
			}
		}
	}
	tSpan=new Array(3);
	var steps=[aStep, gStep, gStep, aStep, gStep, gStep2];
	var m=0;
	for (r=0; r<steps.length; r+=2) {
		var s1=steps[r];
		var s2=steps[r+1];
		var f=s2/s1;
		var max=s2-1;
		a=tSpan[m++]=new Array(s1);
		for (var c=0; c<s1; c++) {
			a[c]=(c==0)? 0: Math.min(max, Math.max(1, Math.round(c*f)));
		}
	}
}

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 getPacRand() {
	pacseed = (pacseed*5+1)&0x1fff;
	return pacseed;
}

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;
	if (!demomode && nScore>hiScore) {
		hiScore=nScore;
		elements.hiscoredisplay.innerHTML=nScore;
	}
}

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

function setLevelIcon(icn) {
	if (icn) {
		fruiticons.push(icn);
		var n=1;
		var i;
		for (i=1; i<8-fruiticons.length; i++) {
			setImage('lvlicon'+n, 'xx');
			n++;
		}
		for (i=fruiticons.length-1; i>=0; i--) {
			if (n>7) break;
			setImage('lvlicon'+n, fruiticons[i]+'s');
			n++;
		}
	}
}


// main

function gameStep() {
	if (gameTimer) clearTimeout(gameTimer);
	var now=new Date();
	enterTime=now.getTime();
	if (gameOn) {
		phaseSet=(!phaseSet);
		if (moved) {
			if (!pill && gameStatus==0 && ++stepCnt>=aStep) {
				stepCnt=0;
				if (--scatterCnt<0) setScatter();
			}
			if (nextGhost) {
				var t=new Date().getTime();
				if (t-foodTimer > maxFoodDelay) {
					g[nextGhost].z=0;
					foodTimer=t;
				}
			}
		}
		switch(gameStatus) {
			case 0: doMove(); break;
			case 1: resetGhost(); break;
			case 2: resetPac(); return;
			case 3: endLevel(); return;
			case 4: startLevel(); break;
		}
		if (--pillBlinkCnt<=0) {
			pillBlinkCnt=pillBlinkDelay;
			pillsVisible=!pillsVisible;
			var img=(pillsVisible)? 'p':'x';
			for (var i=pillPos.length-1; i>=0; i--) {
				var p=pillPos[i];
				if (p[2]) setMaze(p[0],p[1],img);
			}
		}
	}
	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) {
		scatterMode=false;
		if (scatterPhaseCnt < scatterPhase.length-1) scatterPhaseCnt++;
		scatterCnt=scatterPhase[scatterPhaseCnt][0];
	}
	else {
		scatterMode=true;
		scatterCnt=scatterPhase[scatterPhaseCnt][1];
		setupMspacScatter();
	}
	for (var i=1; i<=4; i++) {
		var gi=g[i];
		gi.scnt=0;
		gi.scatter=scatterMode;
		if (gi.s==2) gi.reverse=true;
	}
}

function resetScatter() {
	if (scatterPhaseCnt==0) scatterPhaseCnt++;
	scatterMode=false;
	scatterCnt=scatterPhase[scatterPhaseCnt][0];
}

function setupMspacScatter() {
	mspacScatterOffset = getPacRand()&3;
}

function getMspacScatterPos(i) {
	mspacScatterOffset%=4;
	return (i==2 || i==3)? scatterPos[i]:mspacScatterPos[mspacScatterOffset++];
}

function doMove() {
	var sb=sprites.bonus;
	for (var i=1; i<=5; 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 (fruit) {
		if (fruitMoving) {
			fMove();
		}
		else {
			if (--fruit.z<=0) hideFruit();
		}
	}
	with (pac) {
		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;
			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];
		}
	}
	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) {
			if (pillPeriode) {
				pill=true;
				for (var i=1; i<=4; i++) {
					var gi=g[i];
					if (!gi.pill && gi.s<3) {
						gi.pill=true;
						translateGPos(i,gStep);
						gi.reverse=true;
					}
				}
				pillCnt=pillPeriode*aStep;
				ghostCnt=0;
			}
			else {
				for (var i=1; i<=4; i++) {
					var gi=g[i];
					if (gi.s<3) gi.reverse=true;
				}
			}
			addScore(40);
			if (useSound) playSound('pillbeam');
			if (scatterMode) setScatter();
			stopSound=false;
			for (var i=pillPos.length-1; i>=0; i--) {
				var p=pillPos[i];
				if (p[0]==r && p[1]==c) {
					p[2]=false;
					break;
				}
			}
		}
		else {
			addScore(15);
			if (useSound) playMsPacSound();
		}
		f1[r][c]=0;
		food--;
		if (food==0) {
			if (demomode) {
				endDemo();
			}
			else {
				statusCnt=blinkSteps*blinkRate;
				gameStatus=3;
				g[1].alpha=.75;
				for (i=1; i<=4; i++) {
					var gs=sprites.g[i];
					setOpacity(gs.body, .75);
					setOpacity(gs.eyes, .75);
				}
				if (useSound) playSound('endlevel');
			}
			return;
		}
		else if (food==fruitLimit) {
			fruit=new Ghost();
			if (fruitMoving) {
				fHome();
			}
			else {
				fruit.r=fruit.posy=13;
				fruit.c=fruit.posx=10;
				fruit.z=44*aStep;
				var p = mazePos[13][10];
				moveElement(sprites.fruit.div, p.x, p.y, p.z);
				setVisibility(sprites.fruit.div, true);
			}
		}
		manageGhostPen();
	}
	gmove();
	checkHits();
	if (gameStatus>0) return;
	if (pill) {
		pillCnt--;
		if (pillCnt<=0) {
			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,aStep);
				}
			}
		}
	}
}


// 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, p.y+ofs.y-pacOffsetY, p.z+5);
}

function pMove() {
	with (pac) {
		if (demomode && (!moved || f2[r][c])) pMoveDemo();
		if (dir&movedir) {
			md= dir&movedir;
			touchX=window.touchLastX;
			touchY=window.touchLastY;
			if (!moved) {
				moved=true;
				setVisibility(elements.ready, false);
				foodTimer=new Date().getTime();
			}
		}
		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];
			}
		}
		reversed=false;
	}
}

function pMoveDemo() {
	if (demoCnt<demoCntMax) {
		movedir=demoPath[demoCnt++];
		return;
	}
	var tr=0, tc=0, delta, dx, dy, d, i, p, fd, d;
	var pdelta=10000;
	var x=pac.dir&(15^t3[pac.md]);
	if (pill) {
		delta=Math.floor(pillCnt/aStep);
		delta*=delta;
		for (i=1; i<=4; i++) {
			p=g[i];
			if (p.s==2 && p.pill) {
				dx=pac.c-p.c;
				dy=pac.r-p.r;
				fd=dx*dx+dy*dy;
				//fd=Math.abs(pac.c-p.c)+Math.abs(pac.r-p.r);
				if (fd<delta) {
					tc=p.c;
					tr=p.r;
					delta=fd;
				}
			}
		}
	}
	else {
		delta=pdelta;
		for (i=0; i<4; i++) {
			p=pillPos[i];
			if (p[2]) {
				dy=pac.r-p[0];
				dx=pac.c-p[1];
				fd=dx*dx+dy*dy;
				if (fd<delta) {
					tr=p[0];
					tc=p[1];
					delta=fd;
					pdelta=Math.abs(dx)+Math.abs(dy);
				}
			}
		}
		if (fruit && pdelta>10 && Math.abs(pac.r-fruit.r)+Math.abs(pac.c-fruit.c)<9) {
			tr=fruit.r;
			tc=fruit.c;
		}
	}
	d=0;
	if (tr) {
		var dirs=t2[x];
		var fr = pac.r-tr;
		var fc = pac.c-tc;
		var pd;
		delta=pd=100000000;
		for (var k=0, l=dirs.length; k<l; k++) {
			i=dirs[k];
			dx=fr+ty[i];
			dy=fc+tx[i];
			fd=dx*dx+dy*dy;
			if (fd<delta || (fd==delta && tpd[i]<pd)) {
				d=i;
				delta=fd;
				pd=tpd[i];
			}
		}
	}
	if (d) {
		var x1=x&(15^t3[d]);
		if (x1) {
			delta=(pdelta<5)? pdelta:5;
			for (i=1; i<=4; i++) {
				p=g[i];
				if (p.s==2 && !p.pill && p.d!=d) {
					fd=-1;
					if (pac.c==p.c && ty[d]) {
						fd= (ty[d]<0)? (pac.r-1)-p.r : p.r-(pac.r+1);
					}
					else if (pac.r==p.r && tx[d]) {
						fd= (tx[d]<0)? (pac.c-1)-p.c : p.c-(pac.c+1);
					}
					if (fd>=0 && fd<delta) {
						d=0;
						x=x1;
						break;
					}
				}
			}
		}
	}
	if (!d) {
		var rd=tpf[getPacRand()&0x3f];
		if (x&rd) {
			d=rd;
		}
		else {
			for (i=0; i<4; i++) {
				if (x&tpf[i]) {
					d=tpf[i];
					break;
				}
			}
		}
	}
	movedir=d;
}


// fruit

function fMove() {
	with (fruit) {
		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) {
			hideFruit();
			if (useSound) playSound('assetleave');
		}
		else {
			setFruit();
		}
		if (phaseSet) {
			p+=pn;
			if (p==3) pn=-1;
			if (p==0) pn=1;
		}
	}
}

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

function hideFruit() {
	if (fruit) {
		setVisibility(sprites.fruit.div, false);
		fruit=null;
	}
	if (fruitLimit>food && fruitLimit==fruitLimits[0]) {
		fruitLimit=fruitLimits[1];
		if (fruitMoving && fruitLimit>food-5) {
			fruitLimit=Math.max(1, food-5, Math.floor(food/2));
		}
	}
}


// ghosts

function setGhost(i,r,c) {
	var eyes;
	var gi=g[i];
	var s=gi.s;
	var gc, ofs;
	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>5*aStep) {
			gc=ghostStr.a;
		}
		else {
			gc=(pillCnt%8<4)? ghostStr.n:ghostStr.a;
		}
	}
	else if (s==3) {
		gi.posx=c+gSpan2[gi.osx];
		gi.posy=r+gSpan2[gi.osy];
		ofs=gSpan3D2[gi.osy][gi.osx];
		gc='x';
	}
	else if (gi.tunnel || s==0) {
		gi.posx=c+gSpan[gi.osx];
		gi.posy=r+gSpan[gi.osy];
		ofs=gSpan3D[gi.osy][gi.osx];
		gc=ghostStr[i];
	}
	else {
		gi.posx=c+aSpan[gi.osx];
		gi.posy=r+aSpan[gi.osy];
		ofs=aSpan3D[gi.osy][gi.osx];
		gc=ghostStr[i];
	}
	var eyes;
	var gs=sprites.g[i];
	if (s==3) {
		eyes=eyeRef.homebound;
	}
	else {
		setSpriteImg(gs.bodyimg, gc[gi.p]);
		if (s==0) {
			eyes=eyeRef.home;
		}
		else {
			eyes=(gi.pill)? eyeRef.pill:eyeRef.normal;
		}
	}
	if (s<3) fft[gi.r][gi.c]|=gi.bid;
	if (gi.d!=gi.e) {
		setSpriteImg(gs.eyesimg, eyes[gi.d]);
		gi.e=gi.d;
	}
	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=(++p)%3;
				}
				if (s==2) gMove2pacmode(i)
				else if (s==3) gMove3(i)
				else if (s==1) gMove1(i)
				else if (s==4) gMove4(i)
				else gMove0(i);
			}
		}
		if (g[i].s!=4) displayGhost(i);
	}
}

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

function gMoveEyes(i) {
	if (Math.random()<.01) {
		g[i].d=(Math.random()<.5)? 0 : t2[15][getRand(t2[15].length)];
	}
}

function manageGhostPen() {
	globalHomeCnt++;
	foodTimer=new Date().getTime();
	if (nextGhost) {
		g[nextGhost].homeCnt--;
	}
}

function gMove0(i) {
	with (g[i]) {
		if (moved && nextGhost==i) {
			if (r==10) {// && tileFree(i,9,10)) {
				s++;
				d=4;
				e=-1;
				z=0;
				nextGhost=0;
				if (i==3) {
					resetHomeCnts();
					useGlobalHomeCnt=false;
				}
				else {
					for (var k=1; k<4; k++) {
						if (g[k].s==0) {
							nextGhost=k;
							break;
						}
					}
				}
			}
			if (r==11 && c==10) {
				if (osx) {
					osx+=tx[turn];
					if (osx==0) d=0;
				}
				else if (tileFree(i,10,10)) {
					if (z==0 || (useGlobalHomeCnt && globalHomeCnt>=ghostPenCounts[i]) || (!useGlobalHomeCnt && homeCnt<=0)) {
						d=4;
						e=-1;
						if (--osy==-aStep) {
							osy=0;
							r=10;
						}
					}
					else {
						gMoveEyes(i);
					}
				}
			}
			else if (r==11 && c==9 && tileFree(i,11,10)) {
				turn=d=1;
				c=10;
				osx=1-gStep;
				e=-1;
			}
			else if (r==11 && c==11 && tileFree(i,11,10)) {
				turn=d=2;
				c=10;
				osx=gStep-1;
				e=-1;
			}
			else {
				gMoveEyes(i);
			}
		}
		else {
			gMoveEyes(i);
		}
	}
}

function gMove1(i) {
	with (g[i]) {
		osy--;
		if (osy==-aStep) {
			r=9;
			c=10;
			osx=osy=0;
			d=(i==4 || gLeaveLeft)? 2:1; reverse=pill;
			if (pacseed%256>240) gLeaveLeft=!gLeaveLeft;
			gMove2pacmode(i);
			step = (pill)? gStep:aStep;
			s++;
			e=-1;
		}
	}
}

function gMove2pacmode(i) {
	with (g[i]) {
		if (osx+osy==0) {
			var xtnl=false;
			if (reverse) {
				turn=t3[d];
				reverse=false;
				return;
			}
			else {
				if (turn) d=turn;
				turn=0;
				var xr=trunkBy(r+ty[d],22);
				var xc=trunkBy(c+tx[d],19);
				var x = f2[xr][xc];
				if (x>0) {
					x&=(15^t3[d]);
					if (pill) {
						var rd=tpf[getPacRand()&0x3f];
						if (x&rd) {
							turn=rd;
						}
						else {
							for (var k=0; k<4; k++) {
								if (x&tpf[k]) {
									turn=tpf[k];
									break;
								}
							}
						}
					}
					else {
						if (xr==9 && (xc>=9 && xc<=11)) x&=11;
						var tr, tc;
						if (scatter) {
							var sp = getMspacScatterPos(i);
							tr=sp[0];
							tc=sp[1];
						}
						else {
							switch (i) {
								case 1: // Pinky
									var pd=pac.md;
									tr=pac.r+4*ty[pd];
									tc=pac.c+4*tx[pd];
									if (pd==4) tc-=4;
									break;
								case 2: // Inky
									var pd=pac.md;
									tr=pac.r+2*ty[pd];
									tc=pac.c+2*tx[pd];
									if (pd==4) tc-=2;
									tr += tr-g[4].r;
									tc += tc-g[4].c;
									break;
								case 3: // Clyde (treshold 8 becomes 7 for smaller maze)
									if (Math.abs(pac.r-xr)+Math.abs(pac.c-xc) < 7) {
										tr=scatterPos[3][0];
										tc=scatterPos[3][1];
									}
									else {
										tr=pac.r;
										tc=pac.c;
									}
									break;
								case 4: // Blinky
									tr=pac.r;
									tc=pac.c;
									break;
							}
						}
						if (x) {
							var dirs=t2[x];
							var dsy = xr-tr;
							var dsx = xc-tc;
							var delta=pd=100000000;
							for (var k=0, l=dirs.length; k<l; k++) {
								var n=dirs[k];
								var fr=dsy+ty[n];
								var fc=dsx+tx[n];
								var fd=fr*fr+fc*fc;
								if (fd<delta || (fd==delta && tpd[n]<pd)) {
									turn=n;
									delta=fd;
									pd=tpd[n];
								}
							}
						}
					}
				}
				if (f1[xr][xc]<0) xtnl=true;
			}
			tunnel = (xtnl || f1[r][c]<0)? true:false;
			if (d>0) gSet(i);
		}
		else {
			gSet(i);
		}
	}
}

function gMove3(i) {
	with (g[i]) {
		if (osx+osy==0) {
			if (r==9 && c==10) {
				d=8;
				z=1;
			}
			else if (z) {
				if (i==4 && nextGhost==1 && r==10 && c==9) {
					gHome(i, false);
					return;
				}
				if (r==11 && c==10) {
					if (i==1 || i==4) {
						gHome(i, false);
						return;
					}
					d=(i==2)? 2:1;
				}
				else if (r==11 && c==gHomePos[i][1]) {
					gHome(i, false);
					return;
				}
			}
			else {
				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);
		gi.e=-1;
		var hd = fgh[gi.r][gi.c];
		if (((gi.d & 3) && (hd & 3)) || ((gi.d & 12) && (hd & 12))) gi.d=hd;
		setGhost(i,gi.r,gi.c);
		setSpriteImg(gs.bodyimg, 'x');
		setOpacity(gs.body,1);
		setOpacity(gs.eyes,1);
	}
	else {
		gi.alpha-= (gi.z<ghostResetDelay/2)? ghostResetDelta*2 : ghostResetDelta;
		setOpacity(gs.body, gi.alpha);
	}
}

function gSet(i) {
	with (g[i]) {
		osy+=ty[d];
		osx+=tx[d];
		if (s==3) {
			step=gStep2;
		}
		else if ((pill && s==2) || tunnel || s==0) {
			step=gStep;
		}
		else {
			step=aStep;
		}
		osx%=step;
		osy%=step;
		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 translateGPos(i, nStep) {
	with (g[i]) {
		if (s==2 && nStep!=step) {
			if (tunnel) {
				limitOffsets(g[i], gStep);
				step=gStep;
			}
			else {
				var ts;
				if (step==aStep && nStep==gStep) {
					ts=tSpan[0]
				}
				else if (step==gStep && nStep==aStep) {
					ts=tSpan[1]
				}
				else if (step==gStep && nStep==gStep2) {
					ts=tSpan[2]
				}
				if (ts) {
					osx= (osx<0)? -ts[-osx]:ts[osx];
					osy= (osy<0)? -ts[-osy]:ts[osy];
				}
				step=nStep;
			}
		}
		if (s!=3) e=-1;
	}
}

// hit-test

function checkHits() {
	var crash=false;
	var ghostcatch=false;
	if (fruit && isCollision(fruit.posx,fruit.posy, pac.posx,pac.posy, 0.825)) {
		var pos = mazePos[fruit.r][fruit.c];
		var ofs=gSpan3D[fruit.osy][fruit.osx];
		hideFruit();
		bonus[5]=bonusLength;
		var b=sprites.bonus[5];
		moveElement(b.div, pos.x+ofs.x, pos.y+ofs.y, pos.z+5);
		setSpriteImg(b.img, fruitBonusRef[fruitBonus]);
		setOpacity(b.div, 1);
		setVisibility(b.div, true);
		addScore(fruitBonusVal[fruitBonus]);
		if (useSound) playSound('asseteat');
	}
	for (i=1; i<=4; i++) {
		var gi=g[i];
		if (gi.s==2 && isCollision(gi.posx,gi.posy, pac.posx,pac.posy, 0.95)) {
			var gs=sprites.g[i];
			if (gi.pill) {
				bonus[i]=bonusLength;
				var b=sprites.bonus[i];
				var pos = mazePos[gi.r][gi.c];
				var ofs=gSpan3D[gi.osy][gi.osx];
				var ofs2 = i*3;
				moveElement(b.div, pos.x+ofs.x+ofs2, pos.y+ofs.y-ofs2, pos.z+5);
				setSpriteImg(b.img, 'bonus'+ghostCnt);
				setOpacity(b.div, 1);
				setVisibility(b.div, true);
				addScore(ghostBonus[ghostCnt]);
				if (ghostCnt<3) ghostCnt++;
				gi.tunnel=false;
				translateGPos(i,gStep2);
				var hd = fgh[gi.r][gi.c];
				if ((hd&3 && gi.d&3) || (hd&12 && gi.d&12)) g.d=hd;
				setSpriteImg(gs.bodyimg, 'gx');
				setSpriteImg(gs.eyesimg, eyeRef.homebound[gi.d]);
				setOpacity(gs.body, ghostResetAlpha);
				setOpacity(gs.eyes, ghostResetAlpha);
				gi.alpha=ghostResetAlpha;
				gi.z=ghostResetDelay;
				gi.s=4;
				fft[gi.r][gi.c]&=gi.bm;
				ghostcatch=true;
			}
			else {
				crash=true;
				setOpacity(gs.body, .5);
			}
		}
	}
	if (crash) {
		setSpriteImg(sprites.pac.img, pacStr.x[0]);
		pac.p=0;
		gameStatus=2;
		if (useSound) playSound('pacend');
	}
	else if (ghostcatch) {
		gameStatus=1;
		statusCnt=2;
		if (useSound) playSound('mspghostcatch');
	}
}

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

function resetPac() {
	if (gameTimer) clearTimeout(gameTimer);
	if (pac.p<7) {
		pac.p++;
		setSpriteImg(sprites.pac.img, pacStr.x[pac.p]);
		setOpacity(sprites.pac.div, 1-pac.p/18);
		gameTimer=setTimeout('resetPac()', 174-pac.p*2);
	}
	else {
		if (demomode) {
			endDemo();
			return;
		}
		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);
			}
			//resetHomeCnts();
			useGlobalHomeCnt=true;
			gameStatus=0;
			gameTimer=setTimeout('gameStep()', 100);
		}
		else gameOver();
	}
}

function bonusLife() {
	if (nLife<6) {
		setImage('life'+nLife,'mlife');
		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 gi=g[i];
		var gs=sprites.g[i];
		var a= ((gi.r==13 && gi.c>6 && gi.c<14) || (gi.r==14 && gi.c>7 && gi.c<13))? .4:.6;
		setOpacity(gs.body, a);
		if (!msie) setOpacity(gs.eyes, a);
	}
	if (fruit) setOpacity(sprites.fruit.div, .6);
	if (nScore==hiScore) {
		hiScores[mazeMode]=nScore;
		nScore=0;
	}
	statusCnt=.15;
	gameTimer=setTimeout('showGameOver()', 8);
}

function showGameOver() {
	if (statusCnt<1) {
		statusCnt+=.015;
		if (statusCnt>1) statusCnt=1;
		setOpacity(elements.gameover, statusCnt);
		gameTimer=setTimeout('showGameOver()', 8);
	}
	else {
		demoTimer=setTimeout('showAttractScreen()', 6000);
	}
}

function endLevel() {
	if (gameTimer) clearTimeout(gameTimer);
	var a=g[1].alpha-=.015;
	for (var i=1; i<=4; i++) {
		var gs=sprites.g[i];
		setOpacity(gs.body, a);
		//setOpacity(gs.eyes, a);
	}
	if (fruit) setOpacity(sprites.fruit.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);
		}
		gameStatus=4;
		gameTimer=setTimeout('gameStep()', 37);
	}
	else {
		gameTimer=setTimeout('endLevel()', 37);
	}
}

function doPause() {
	if (gameStatus>=0 && !demomode) {
		if (gameOn) {
			setVisibility(elements.gamepaused, true);
			setVisibility(elements.ready, false);
			gameOn=false;
			isPause=true;
		}
		else {
			setVisibility(elements.gamepaused, false);
			if (!moved) setVisibility(elements.ready, true);
			gameOn=true;
			isPause=false;
			foodTimer=new Date().getTime();
		}
	}
}

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, .2);
	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 (!demomode) {
			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=="p" || k==27) {
				doPause();
			}
		}
		if (ch=="n") {
			if ((gameOn || isPause) && nScore>0 && !demomode) {
				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;
}

// high scores & cookies
var preferencesName='mspac3dPreferences';
var legalPrefsValues = {
	'speed': [0,1,2,3],
	'quality': [0,1,2],
	'mazemode': ['MsPacman','MsPacmanPlus','GhostsLevels','Shuffle']
};
var cookieLifeSpan = 366 * 24 * 60 * 60 * 1000;
var oldCookiesCleaned=false;

function savePreferences() {
	var now = new Date();
	now.setTime( now.getTime() + cookieLifeSpan );
	var suffix = '; expires=' + now.toGMTString()+'; path=/JavaPac/';
	var hs='';
	var hskeys=legalPrefsValues.mazemode;
	for (var i=0; i<hskeys.length; i++) {
		var k=hskeys[i];
		hs+=k+'['+hiScores[k]+']';
	}
	var prefs= [
		'speed:'+settingsSpeedValue,
		'quality:'+settingsQualityValue,
		'mazemode:'+mazeMode,
		'hiscore:'+hs
	];
	if (window.soundCurrentVolume!=undefined) {
		prefs.push('volume:'+ Math.round(soundCurrentVolume*1000)/1000);
	}
	if (oldCookiesCleaned) {
		prefs.push('cleanup:1');
	}
	document.cookie=preferencesName+'='+escape(prefs.join(','))+suffix;
}

function readPreferences() {
	var parts = document.cookie.split(';');
	var hsPrefs=false;
	for ( var i = 0; i < parts.length; i++ ) {
		var temp = parts[i].split('=');
		if (temp.length>=2 && getTrimmedString(temp[0])==preferencesName) {
			var prefs=unescape(temp[1]);
			var prefParts=prefs.split(',');
			for (var k=0; k<prefParts.length; k++) {
				var p=prefParts[k].split(':',2);
				var key=getTrimmedString(p[0]);
				var val=getTrimmedString(p[1]);
				var v;
				switch (key) {
					case 'speed':
						v=parseInt(val,10);
						if (!isNaN(v) && isLegalPrefsValue(key,v)) settingsSpeedValue=v;
						break;
					case 'quality':
						v=parseInt(val,10);
						if (!isNaN(v) && isLegalPrefsValue(key,v)) settingsQualityValue=v;
						break;
					case 'mazemode':
						if (isLegalPrefsValue(key,val)) mazeMode=val;
						break;
					case 'hiscore':
						var hsparts=val.split(']');
						for (var j=0; j<hsparts.length; j++) {
							var hsp=hsparts[j].split('[');
							var hsk=getTrimmedString(hsp[0]);
							var v=parseInt(hsp[1],10);
							if (!isNaN(v) && isLegalPrefsValue('mazemode',hsk)) hiScores[hsk]=v;
						}
						hsPrefs=true;
						break;
					case 'volume':
						v=parseFloat(val);
						if (!isNaN(v) && v>=0 && v<=1 && window.setSoundVolume) {
							setSoundVolume(v);
						}
						break;
					case 'cleanup':
						oldCookiesCleaned=true;
						break;
				}
			}
			break;
		}
	}
	if (!hsPrefs) checkOldHiScores();
	var hskeys=legalPrefsValues.mazemode;
	for (var i=0; i<hskeys.length; i++) {
		var k=hskeys[i];
		if (hiScores[k]==undefined) hiScores[k]=0;
	}
	if (!oldCookiesCleaned) cleanOldCookies();
	if (!hsPrefs) savePreferences();
}

function getTrimmedString(s) {
	if (!s) return '';
	return s.replace(/^\s+/, '').replace(/\s+$/, '');
}

function isLegalPrefsValue(k,v) {
	var a=legalPrefsValues[k];
	if (a) {
		for (var i=0; i<a.length; i++) {
			if (a[i]==v) return true;
		}
	}
	return false;
}

function resetHiScores() {
	if (!confirm('Sure to reset the high score on this machine?')) return;
	var keys=legalPrefsValues.mazemode;
	for (var i=0; i<keys.length; i++) {
		hiScores[keys[i]]=0;
	}
	savePreferences();
	setMazeMode(mazeMode, false);
}

function cleanOldCookies() {
	var hsPrefix='mspacHS';
	var settingsPrefix='mspacSettings';
	var settingsKeys=['Speed','Quality'];
	if (String(document.cookie).indexOf(settingsPrefix+settingsKeys[0]+'=')>=0) {
		var now=new Date();
		now.setTime(now.getTime()-1);
		var suffix = '=; expires=' + now.toGMTString();
		var hskeys=legalPrefsValues.mazemode;
		for (var i=0; i<hskeys.length; i++) {
			document.cookie=hsPrefix+hskeys[i]+suffix;
		}
		for (i=0; i<settingsKeys.length; i++) {
			document.cookie=settingsPrefix+settingsKeys[i]+suffix;
		}
	}
	oldCookiesCleaned=true;
}

// old hiscore api

function checkOldHiScores() {
	var hsprefix='mspacHS';
	var vars=getCookieVars();
	var hskeys=legalPrefsValues.mazemode;
	for (var i=0; i<hskeys.length; i++) {
		var k=hskeys[i];
		var v=parseInt(vars[hsprefix+k],10);
		if (!isNaN(v)) hiScores[k]=v;
	}
}

function getCookieVars() {
	var obj = new Object();
	var parts = document.cookie.split(';');
	for ( var i = 0; i < parts.length; i++ ) {
		var temp = parts[i].split('=');
		if (temp.length>=2) {
			var key = temp[0].replace(/^\s+|\s+$/g, '');
			var val = unescape( temp[1].replace(/^\s+|\s+$/g, '') );
			obj[key]=val;
		}
	}
	return obj;
}

// trigger

setTimeout('init()', 500);


onunload=function() {
	elements=sprites=null;
	try {
		if (gameOn && nScore && nScore==hiScore && hiScores[mazeMode]!=nScore) {
			hiScores[mazeMode]=nScore;
		}
		savePreferences();
	}
	catch(e) {}
}

// eof