//////////////////////////////////////////////////////////////////////////////
//                                                                          //
// Wii Opera SDK - Raycasting v1.8.10 2008-12-14                            //
// (c) 2007-2008 Daniel Gump. All Rights Reserved.                          //
// http://wiioperasdk.com, http://hullbreachonline.com                      //
// hullbreach@hullbreachonline.com                                          //
//                                                                          //
//  Wii is a trademark of Nintendo Co., Ltd.                                //
//  Opera is a trademark of Opera, ASA.                                     //
//  This software package is not associated with either company             //
//  but was created to support users of both.  Its alternative name         //
//  when supporting other products is the HULLBREACH SDK.                   //
//                                                                          //
//  Redistribution and use in source and binary forms, with or without      //
//  modification, are permitted provided that the following conditions      //
//  are met:                                                                //
//    * Redistributions of source code must retain the above copyright      //
//      notice, this list of conditions and the following disclaimer.       //
//    * Redistributions in binary form must reproduce the above copyright   //
//      notice, this list of conditions and the following disclaimer in     //
//      the documentation and/or other materials provided with the          //
//      distribution.                                                       //
//    * Neither the names HULLBREACH ONLINE nor WII OPERA SDK nor the names //
//      of its contributors may be used to endorse or promote products      //
//      derived from this software without specific prior written           //
//      permission.                                                         //
//    * If the explicit purpose of the software is not to support the       //
//      Nintendo Wii or the Opera Web browser, then the names of such must  //
//      not be used in any derived product. The name shall be the           //
//      HULLBREACH SDK with a reference link to http://hullbreachonline.    //
//                                                                          //
//  THIS SOFTWARE IS PROVIDED BY Daniel Gump ''AS IS'' AND ANY EXPRESS OR   //
//  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED          //
//  WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE  //
//  DISCLAIMED. IN NO EVENT SHALL Daniel Gump BE LIABLE FOR ANY DIRECT,     //
//  INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES      //
//  (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR      //
//  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)      //
//  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,     //
//  STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING   //
//  IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE      //
//  POSSIBILITY OF SUCH DAMAGE.                                             //
//////////////////////////////////////////////////////////////////////////////
function RayCast(){
	//Canvas size
	WIDTH=240; HEIGHT=176;
	//Player's coordinates
	X=1.5; Y=1.5;
	U=0; V=1;
	PLANEU=1; PLANEV=0;
	ANGLE=0;
	ROTATESPEED=.2; MOVESPEED=.2;
	WALLSCENE=[]; TEXTURES=[]; TELEPORTS=[];
	CANVAS=null;
	SKYFILL='rgb(0,0,0)'; GROUNDFILL='rgb(0,0,0)';
	COLLISION=0;
}
RayCast.prototype.generateScene = function(){
	CANVAS.fillStyle=SKYFILL;
	CANVAS.fillRect(0,0, WIDTH,HEIGHT>>1);
	CANVAS.fillStyle=GROUNDFILL;
	CANVAS.fillRect(0,HEIGHT>>1, WIDTH,HEIGHT);

	//Player location
	var rayX=X, rayY=Y;
	//Ray length data
	var sideDistX, sideDistY;
	//Stepping data
	var stepX, stepY;
	var side, hit;

	for(var column=WIDTH, camerastep = 2/WIDTH; column>=0; column-=8){
		//Ray length
		var deltaDistX = Math.sqrt(1+((rayV=V+PLANEV*(cameraX = column*camerastep-1))*rayV)/((rayU=U+PLANEU*cameraX)*rayU));
		var deltaDistY = Math.sqrt(1+(rayU*rayU)/(rayV*rayV));

		//Find initial side dist
		stepX = stepY = -1;
		sideDistX = rayX-(mapX=X|0);
		sideDistY = rayY-(mapY=Y|0);

		if(rayU>=0){
			stepX = 1;
			sideDistX = 1-sideDistX;
		}
		if(rayV>=0){
			stepY = 1;
			sideDistY = 1-sideDistY;
		}
		sideDistX*=deltaDistX;
		sideDistY*=deltaDistY;

		//Step DDA
		do{
			if(sideDistX<sideDistY){
				sideDistX+=deltaDistX;
				mapX+=stepX;
				side=0;
			}else{
				sideDistY+=deltaDistY;
				mapY+=stepY;
				side=1;
			}
		}while(!(hit=WALLSCENE[mapX][mapY]));

		var drawStart = ((HEIGHT-(lineHeight=HEIGHT/((perpWallDist=(!side)?(mapX-rayX+(1-stepX)*.5)/rayU:(mapY-rayY+(1-stepY)*.5)/rayV)>>31?-perpWallDist:perpWallDist)))>>1)+(walkBounce=HEIGHT/(10*perpWallDist));
		var drawEnd = ((lineHeight+HEIGHT)>>1)-drawStart;

		var wallX = side?rayX+perpWallDist*rayU:rayY+perpWallDist*rayV;
		var texX = ((wallX-(wallX|0))*(texture=TEXTURES[WALLSCENE[mapX][mapY]]).width)|0;
		if((!side && rayU>0) || (side && rayV<0)) texX = (texture.width-texX-1)>>1;

		var top=0;

		if(drawStart<0){
			top=((1-HEIGHT/(HEIGHT-(drawStart<<1)))*(texture.height>>1))>>1;
			drawStart=0;
			drawEnd=HEIGHT;
		}
		CANVAS.drawImage(texture, texX,top, 1,(texture.height>>1)-top, column,drawStart, 8,drawEnd);
	}
}
RayCast.prototype.loadScene = function(array){
	if(WALLSCENE = array.split(';')) for (i=WALLSCENE.length;--i>=0;) WALLSCENE[i] = WALLSCENE[i].split(',');
}
RayCast.prototype.moveForward = function(){
	COLLISION=1;
	if(!WALLSCENE[(X+U*MOVESPEED)|0][Y|0]){
		X+=U*MOVESPEED;
		COLLISION=0;
	}
	if(!WALLSCENE[X|0][(Y+V*MOVESPEED)|0]){
		Y+=V*MOVESPEED;
		COLLISION=0;
	}
}
RayCast.prototype.moveBackward = function(){
	COLLISION=1;
	if(!WALLSCENE[(X-U*MOVESPEED)|0][Y|0]){
		X-=U*MOVESPEED;
		COLLISION=0;
	}
	if(!WALLSCENE[X|0][(Y-V*MOVESPEED)|0]){
		Y-=V*MOVESPEED;
		COLLISION=0;
	}
}
RayCast.prototype.moveLeft = function(){
	COLLISION=1;
	if(!WALLSCENE[(X-V*MOVESPEED)|0][Y|0]){
		X-=V*MOVESPEED;
		COLLISION=0;
	}
	if(!WALLSCENE[X|0][(Y+U*MOVESPEED)|0]){
		Y+=U*MOVESPEED;
		COLLISION=0;
	}
}
RayCast.prototype.moveRight = function(){
	COLLISION=1;
	if(!WALLSCENE[(X+V*MOVESPEED)|0][Y|0]){
		X+=V*MOVESPEED;
		COLLISION=0;
	}
	if(!WALLSCENE[X|0][(Y-U*MOVESPEED)|0]){
		Y-=U*MOVESPEED;
		COLLISION=0;
	}
}

RayCast.prototype.checkTeleports = function(){
	for(tele=TELEPORTS.length;--tele>=0;){
		if(TELEPORTS[tele][0]==.5+(Y|0) && TELEPORTS[tele][1]==.5+(X|0)){
			if(TELEPORTS[tele][4]) document.location.href = TELEPORTS[tele][4];
			Y = TELEPORTS[tele][2];
			X = TELEPORTS[tele][3];
		}
	}
}
RayCast.prototype.isCollided = function(){ return COLLISION; }
RayCast.prototype.setAltitude = function(alt){ ALTITUDE=alt>=-5*HEIGHT?(alt<=5*HEIGHT?alt:5*HEIGHT):-5*HEIGHT; }
RayCast.prototype.setDirection = function(angle){
	U = Math.sin(ANGLE=angle*0.0174533);
	V = Math.cos(ANGLE);
	PLANEU = Math.sin(ANGLE+1.5707963);
	PLANEV = Math.cos(ANGLE+1.5707963);
}
RayCast.prototype.setGroundColor = function(r,g,b){ GROUNDFILL="rgb("+(r<0?0:(r>255?255:r|0))+","+(g<0?0:(g>255?255:g|0))+","+(b<0?0:(b>255?255:b|0))+")"; }
RayCast.prototype.setLocation = function(x,y){ X=y; Y=x; }
RayCast.prototype.setSize = function(w,h){ WIDTH=w; HEIGHT=h; }
RayCast.prototype.setSkyColor = function(r,g,b){ SKYFILL="rgb("+(r<0?0:(r>255?255:r|0))+","+(g<0?0:(g>255?255:g|0))+","+(b<0?0:(b>255?255:b|0))+")"; }
RayCast.prototype.setTeleports = function(teleports){ TELEPORTS=teleports; }
RayCast.prototype.setTextures = function(textures){ TEXTURES=textures; }
RayCast.prototype.setWalls = function(Walls){ WALLSCENE = Walls; }
RayCast.prototype.initialize = function(canvas){ CANVAS = canvas.getContext("2d"); }

RayCaster = new RayCast();