<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> <meta http-equiv="Content-Style-Type" content="text/css"> <meta http-equiv="content-language" content="en"> <title>HylZee</title> <!--META HTTP-EQUIV="Expires" CONTENT="Fri, Jan 01 1900 00:00:00 GMT"--> <!-- commented out, seems to affect images META HTTP-EQUIV="Pragma" CONTENT="no-cache"--> <!--META HTTP-EQUIV="Cache-Control" CONTENT="no-cache"--> <meta name="author" content="peter.schaefer@gmail.com"> <META HTTP-EQUIV="Reply-to" CONTENT="peter.schaefer@gmail.com"> <meta name="generator" content="Code Monkey 1970.01.18(tm Peter Schaefer)"> <META NAME="description" CONTENT="HylZee - A DHTML puzzle game"> <meta name="keywords" content="HylZee DHTML javascript puzzle game huelsi tal pyr"> <META NAME="Creation_Date" CONTENT="09.10.2004"> <meta name="revisit-after" content="30 days">
<link rel="shortcut icon" type="image/x-icon" href="favicon.ico" src="favicon.ico">
<!-- copyright 2004 peter schaefer --> <!-- This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. -->
<style type="text/css">
b {font-size:16px;}
.map {color:white;} .controlembossed { background: #66CC33; border-top-style:solid; border-right-style:solid; border-bottom-style:solid; border-left-style:solid; border-top-width: 1px; border-right-width: 1px; border-bottom-width: 1px; border-left-width: 1px; border-right-color: #99FF66; border-top-color: #99FF66; border-left-color: #666666; border-bottom-color: #666666; } a:link { color: #99FF66; } a:hover { color: #FFFF66; } a:active { color: #FF9966; } a:visited { color: #66FF33; }
table,tbody,th,td,img,span { margin-left: 0px; margin-top: 0px; margin-right: 0px; margin-bottom 0px; padding-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; }
</style>
<script language="JavaScript" type="text/JavaScript"> <!--
// placement of map window var map_top= 18; var map_left= 20;
// grid size of map tiles var cell_height=32; var cell_width= cell_height;
// size of bullet graphics var bullet_width= 12; var bullet_height= 12; var status_font= 18;
//status bar minimum width var minStatusbarWidth= 10*32;
var tileset="default"
// number of space units/tile var step_unit= 100;
// number of ticks/1 tile movement var ticks_unit= 420;
// ticks/processing of mainLoop //FIXME: this doesn't work with 40/240; var theTick= 42;
// frequency of mainloop var mainDelay= 20;
// which level to load var lastLevel= "maps/test/devel-001.html";
// show shrinking animations var shrink= true;
//continue running var mainProceed= true;
var debug= false;
// // debugall switches on most annoying debug output // var debugall= true;
var hideDebug= true || debug;
//input constants var key_fire= 70; var key_right= 39; var key_down= 40; var key_up= 38; var key_left= 37;
//map object var map= null;
//log repeat functionality var log_lastMsg=""; var log_count=0; var log_threshold=2; var log_limit=3000;
//which codes signal start and home var code_start='A'; var code_home ='H';
// // arguments.caller has been deprecated // So the stacktrace will not work in new browsers // function funcname(f) { var s = f.toString().match(/function (w*)/)[1]; if ((s == null) || (s.length==0)) return "anonymous"; return s; }
function stacktrace() { if(!arguments.caller) { return "no stacktrace available"; }
var s = ""; for (var a = arguments.caller; a !=null; a = a.caller) { s += "->"+funcname(a.callee) + "n"; if (a.caller == a) {s+="*"; break;} } return s; }
function debugMsg(message) { if(debug) { //window.status= message; if(log_lastMsg!=message) { log_lastMsg=message; log_count=0; log_threshold=2; message="<br>"+message; }else { log_count++; if(log_count>=log_threshold) { message= "<br>last message repeated "+log_count+" more times."; log_threshold<<=1; log_count=0; }else { message=""; } }
if(message) { var debugDiv= document.getElementById("debugoutput"); if(debugDiv){ var startpos= (debugDiv.innerHTML.length>log_limit)?(debugDiv.innerHTML.length-log_limit):0; debugDiv.innerHTML= debugDiv.innerHTML.substring(startpos, debugDiv.innerHTML.length)+message; }else if(debug && debugall) { alert("debugMsg "+log_lastMsg+" (page isn't loaded yet/no debug window found)"); debugall= false; }
} } }
function debugEval(test) { debugMsg(test+"="+eval(test)); }
function showLayer(layer) { var div= document.getElementById(layer); if(div) div.style.visibility = 'visible'; }
function hideLayer(layer) { var div= document.getElementById(layer); if(div) div.style.visibility = 'hidden'; }
// the fudge factor is used to work around math rounding errors var fudge= 0.000001;
function toGridX(x) { return Math.floor(x/step_unit+fudge); }
function toGridY(y) { return Math.floor(y/step_unit+fudge); }
function toScreenX(x) { return map_left+Math.floor(x*cell_width+fudge); }
function toScreenY(y) { return map_top+Math.floor(y*cell_height+fudge); }
var protagonist=null; var gameState=null;
var Coordinate_toString= function() { return '('+this.x+','+this.y+')'; }
function Coordinate_copy() { return new Coordinate(this.x,this.y); }
function Coordinate_clip() { var clipped= false; if( this.x<-fudge ) { this.x=0; clipped= true; } else if( this.x-fudge>step_unit*(map.xmax-1) ) { this.x= step_unit*(map.xmax-1); clipped= true; }
if( this.y<-fudge ) { this.y=0; clipped= true; } else if( this.y-fudge>step_unit*(map.ymax-1) ) { this.y= step_unit*(map.ymax-1); clipped= true; } return clipped; }
function Coordinate_add(coordinate) { this.x+= coordinate.x; this.y+= coordinate.y; }
function Coordinate_gridLock() { this.x= step_unit*Math.floor((this.x+step_unit/2+fudge)/step_unit); this.y= step_unit*Math.floor((this.y+step_unit/2+fudge)/step_unit); }
function Coordinate(x,y) { this.x= x; this.y= y; //methods this.clip= Coordinate_clip; this.toString= Coordinate_toString; this.add= Coordinate_add; this.copy= Coordinate_copy; this.gridLock= Coordinate_gridLock; }
function toName() { return 'Avatar of:'+this.name; }
function Avatar(name,modifier,facing) { this.name= name; this.modifier= modifier; this.facing= facing;
//methods this.toString= toName; }
// // image preloading // var myImages= new Array(); function loadImages() { for (i=0;i<loadImages.arguments.length;i++) { var pos= myImages.length; myImages[pos]=new Image(); myImages[pos].src= loadImages.arguments[i]; } }
function imagePath(imageName) { return 'images/'+tileset+'/'+imageName; }
var browsercaps= new Object();
//get internal browser representation/ordering of html function fixHTML(html) { if(browsercaps.fixHTML) { var div= document.getElementById("scratchpad"); div.innerHTML= html; return div.innerHTML; }else{ return html; } }
// // Some browser, like gecko, covert innerHTML to canonic representation. // this causes flickering // function debugHTMLrep(text){ var fixed= fixHTML(text); if( fixed!= text) { debugMsg("txt:"+escape(text)); debugMsg("fix:"+escape(fixed)); } }
function Direction_normalize(direction) { if(direction<0) direction= (direction- 360*Math.floor(direction/360+fudge)) direction= (direction+360)%360; return direction; }
// // This function almost works for all agents // function Protagonist_mapToImage() { this.image="protagonist"; if(this.mode) { this.image+= "_"+this.mode; }
if(this.mode!="victorious") { if(this.facing>=0 && this.facing<=45) this.image+= "_right"; else if(this.facing>=45 && this.facing<=135) this.image+= "_up"; else if(this.facing>=135 && this.facing<=225) this.image+= "_left"; else if(this.facing>=225 && this.facing<=315) this.image+= "_down"; else if(this.facing>=315 && this.facing<=360) this.image+= "_right"; else { var msg='mapToImage: ('+this.facing+', bad facing)'; debugMsg(msg); } }
this.image+="_64.gif";
return this.image; }
var bullet_right= new Avatar('bullet_small','right',0); var bullet_up= new Avatar('bullet_small','up',90); var bullet_left= new Avatar('bullet_small','left',180); var bullet_down= new Avatar('bullet_small','down',270);
var bird_right= new Avatar('phoenix_moving','right',0); var bird_up= new Avatar('phoenix_moving','up',90); var bird_left= new Avatar('phoenix_moving','left',180); var bird_down= new Avatar('phoenix_moving','down',270);
var siren_right= new Avatar('chess-rook_moving','right',0); var siren_up= new Avatar('chess-rook_moving','up',90); var siren_left= new Avatar('chess-rook_moving','left',180); var siren_down= new Avatar('chess-rook_moving','down',270);
function getSirenForDirection(direction) { direction= Direction_normalize(direction);
if(direction>=0 && direction<=45) return siren_right; else if(direction>=45 && direction<=135) return siren_up; else if(direction>=135 && direction<=225) return siren_left; else if(direction>=225 && direction<=315) return siren_down; else if(direction>=315 && direction<=360) return siren_right; else { var avatar= 'getSiren: fuck up('+direction+', bad argument)'; debugMsg(avatar); return null; } }
function getBirdForDirection(direction) { direction= Direction_normalize(direction);
if(direction>=0 && direction<=45) return bird_right; else if(direction>=45 && direction<=135) return bird_up; else if(direction>=135 && direction<=225) return bird_left; else if(direction>=225 && direction<=315) return bird_down; else if(direction>=315 && direction<=360) return bird_right; else { var avatar= 'getBird: fuck up('+direction+', bad argument)'; debugMsg(avatar); return null; } }
//FIXME: replace all the verbatim stuff with imagePath(imageName) function mapCodeToImage(code){ var src=''; switch(code) {
case 'H':src='images/'+tileset+'/'+'house_64.gif'; break; case 'h':src='images/'+tileset+'/'+'house_open_64.gif'; break;
case 'K':src='images/'+tileset+'/'+'ball_red_64.gif'; break; case 'I':src='images/'+tileset+'/'+'ball_blue_64.gif'; break; case 'J':src='images/'+tileset+'/'+'ball_green_64.gif'; break;
case 'L':src='images/'+tileset+'/'+'box_blue_64.gif'; break;
case 'C':src='images/'+tileset+'/'+'bricks_red_64.gif'; break; case 'g':src='images/'+tileset+'/'+'bricks_green_64.gif'; break; case 'N':src='images/'+tileset+'/'+'bricks_grey_64.gif'; break;
case 'M':src='images/'+tileset+'/'+'centerstone-blue_64.gif'; break; case 'O':src='images/'+tileset+'/'+'centerstone-grey_64.gif'; break;
case 'R':src='images/'+tileset+'/'+'phoenix_sleeping_left_64.gif'; break; case 'S':src='images/'+tileset+'/'+'phoenix_sleeping_up_64.gif'; break; case 'T':src='images/'+tileset+'/'+'phoenix_sleeping_right_64.gif'; break; case 'U':src='images/'+tileset+'/'+'phoenix_sleeping_down_64.gif'; break;
case 'r':src='images/'+tileset+'/'+'phoenix_awake_left_64.gif'; break; case 's':src='images/'+tileset+'/'+'phoenix_awake_up_64.gif'; break; case 't':src='images/'+tileset+'/'+'phoenix_awake_right_64.gif'; break; case 'u':src='images/'+tileset+'/'+'phoenix_awake_down_64.gif'; break;
case 'P':src='images/'+tileset+'/'+'chess-rook_sleeping_left_64.gif'; break; case 'p':src='images/'+tileset+'/'+'chess-rook_awake_left_64.gif'; break;
case 'P.right':src='images/'+tileset+'/'+'chess-rook_sleeping_right_64.gif'; break; case 'p.right':src='images/'+tileset+'/'+'chess-rook_awake_right_64.gif'; break;
case 'p.moving.left':src='images/'+tileset+'/'+'chess-rook_moving_left_64.gif'; break; case 'p.moving.up':src='images/'+tileset+'/'+'chess-rook_moving_up_64.gif'; break; case 'p.moving.right':src='images/'+tileset+'/'+'chess-rook_moving_right_64.gif'; break; case 'p.moving.down':src='images/'+tileset+'/'+'chess-rook_moving_down_64.gif'; break;
//FIXME: this should be handled more elegantly by checking for code.mapToImage and writing adding mapToImage function to avatar case bullet_right: case bullet_left: case bullet_up: case bullet_down:
case siren_right: case siren_left: case siren_up: case siren_down:
case bird_right: case bird_left: case bird_up: case bird_down: src='images/'+tileset+'/'+code.name+'_'+code.modifier+'_64.gif'; //debugMsg('setting image:'+src); break;
case 'Z':src='images/'+tileset+'/'+'cone_up_64.gif'; break; case '[':src='images/'+tileset+'/'+'cone_down_64.gif'; break;
case 'bullet_big':src='images/'+tileset+'/'+'bullet_big_right_64.gif'; break;
case 'background':src='images/'+tileset+'/'+'background.gif'; break;
default: src=''; } return src; }
function mapCodeToHtml(code,width,height) { var box=""; var imgsrc= mapCodeToImage(code); if(imgsrc) { box+='<img src="'+imgsrc+'" alt="'+code+'" title="'+code+'" style="margin: 0px;" border="0" height="'+Math.floor(height)+'" width="'+Math.floor(width)+'">'; if(debug && debugall) { debugHTMLrep(box); } } else { switch( code ){ case '_': case ' ': case 'A': box= " "; break; default: box= " "+code+" "; } } return box; }
function Snapshot(what,pos,zoom,time) { this.what= what; this.pos= pos; this.zoom= zoom; this.time= time; }
function Code_animate(t) {
var completed= (t-this.a.time)/(this.b.time-this.a.time); var zoom = this.b.zoom*completed+this.a.zoom*(1.0-completed); var posx= this.b.pos.x*completed+this.a.pos.x*(1.0-completed); var posy= this.b.pos.y*completed+this.a.pos.y*(1.0-completed);
var pos= new Coordinate(posx,posy);
//note: clipping suffers badly from bad math which gives >xmax*step_ if( pos.clip() ) { this.b.time=t;//FIXME:zayin ba debug! }
if(this.updateObj && this.updateObj.update) { this.updateObj.update(pos); }
var animDiv= document.getElementById(this.div); if(animDiv) { animDiv.style.left= toScreenX(pos.x/step_unit+(1.0-zoom)*0.5); animDiv.style.top= toScreenY(pos.y/step_unit+(1.0-zoom)*0.5);
var node= mapCodeToNode(this.a.what,cell_width*zoom,cell_height*zoom,animDiv.id); if(node!= animDiv.firstChild){ clearChildren(animDiv); animDiv.appendChild(node); } //this redraw often isn't necessary => don't redraw // var text= mapCodeToHtml(this.a.what,cell_width*zoom,cell_height*zoom); // //text= fixHTML(text); // fixed already !? // if(text!=animDiv.innerHTML) // animDiv.innerHTML= text; } else { debugMsg("Error: no layer left for animations"); } }
var animation_divs= new Array();
function Animation_begin() { this.finished= false; this.hasChanged= true; for(var i=0; i<1000; ++i) { if(!animation_divs[i]) { animation_divs[i]= "animation"+i; this.divid= i; this.div= animation_divs[this.divid]; //var animDiv= document.getElementById(this.div); //animDiv.innerHTML=""; showLayer(this.div); break; } } }
function Animation_end() {
if(this.div) {
var animDiv= document.getElementById(this.div); animDiv.innerHTML=""; hideLayer(this.div); animation_divs[this.divid]= null; this.div= null; this.hasChanged= true; }
//avoid endless recursion if(!this.finished) { this.finished= true; if(this.updateObj && this.updateObj.finish) { this.updateObj.finish(); } }
}
function Animation(a,b,updateObj) { this.a= a; this.b= b; this.updateObj= updateObj;
this.animate= Code_animate;
this.begin= Animation_begin; this.end= Animation_end; }
var mapRaw= new Array( new Array('_','_','_','C','_','M','N','O','_','_','_','_'), new Array('_',' ','A','L',' ',' ',' ',' ',' ',' ','P','_'), new Array('_','K',' ','g','g',' ',' ',' ',' ',' ',' ','_'), new Array(' ','I',' ',' ','g',' ',' ',' ','?,' ',' ','_'), new Array('I','J',' ','N','N','N',' ',' ',' ',' ',' ','_'), new Array('I',' ',' ','N','N','N',' ','Z',' ',' ','U','_'), new Array(' ',' ',' ',' ',' ',' ',' ','[',' ',' ',' ','_'), new Array(' ',' ','L',' ','Z',' ',' ',' ','T',' ',' ','_'), new Array(' ','N','[',' ','L',' ',' ',' ','T',' ',' ','R'), new Array('R','P','_','_','_','_','H','_','_','S','_','_') );
var notnagel=0;
// // scans the map for an object specified by 'code' // function is notorious for hanging the program .. // function Map_scan(code,last) { if(Map_scan.arguments.length<2) { x= 0; y= 0; } else if(!last) { x= 0; y= 0; } else { x= toGridX(last.x)+1; y= toGridY(last.y); notnagel++; // if(notnagel>100) { // debugMsg("halting"); // gameProceed= false; // sleep(1000); // notnagel=0; // } //debugMsg("last:"+last+" x "+x+" y"+y); }
//for y for x while(true) { if(x>=this.xmax) { x= 0; y= y+1; if(y>=this.ymax) { return null; } }
if(this.map[y][x]==code) { var c= new Coordinate(x*step_unit,y*step_unit); return c; }
x= x+1; }
}
function fromDirection(direction) { direction= Direction_normalize(direction); if(direction>=0 && direction<=45) return this.right; else if(direction>=45 && direction<=135) return this.up; else if(direction>=135 && direction<=225) return this.left; else if(direction>=225 && direction<=315) return this.down; else if(direction>=315 && direction<=360) return this.right; else { var msg= 'fuck up('+this.direction+', bad argument)'; debugMsg(msg); return this.none; } }
function Compass(scale) { if(!scale) { scale=1; } this.none= new Coordinate(0,0);
this.right= new Coordinate(scale,0); this.up= new Coordinate(0,-scale); this.left= new Coordinate(-scale,0); this.down= new Coordinate(0,scale);
//methods this.fromDirection= fromDirection; }
var compass= new Compass(); var stepcompass= new Compass(step_unit);
function scanTrap(code,direction,from,checkObstacle,checkForTarget) { var delta= stepcompass.fromDirection(direction);
var pos= from.copy();
pos.add(delta);
while(!pos.clip()) { if( checkObstacle(code,pos) ) return false; if( checkForTarget(code,pos,from) ) return true; pos.add(delta); } return false; }
function getXYCode(x,y) { x= Math.floor(x+fudge); y= Math.floor(y+fudge); if(!this.map[y]) { debugMsg("bad x,y in getXYCode x:"+x+" y:"+y); } return this.map[y][x]; }
function setXYCode(x,y,code) { x= Math.floor(x+fudge); y= Math.floor(y+fudge); this.mapHasChanged= true; this.map[y][x]=code; }
function Map_addAnimation(animation) { var len= this.animations.length; for(var i=0; i<len+1; ++i) { if(!this.animations[i]) { this.animations[i]= animation; break; } } animation.begin(); }
function Map_removeAnimation(animation) { var len= this.animations.length; for(var i=0; i<len+1; ++i) { if(this.animations[i]==animation) { animation.end(); this.animations[i]= null; break; } } }
function Map_cleanAnimations(t) { var len= this.animations.length; for(var i=0; i<len; ++i) { if(this.animations[i] && this.animations[i].b && this.animations[i].b.time<=t) { this.removeAnimation(this.animations[i]); } } }
function GameState_addBullet(bullet) { map.addAnimation(bullet.animation); gameState.bullet= bullet; }
function GameState_removeBullet(bullet) { map.removeAnimation(bullet.animation); this.bullet= null; }
function GameState_addMover(mover) { map.addAnimation(mover.animation); this.mover= mover; }
function GameState_removeMover(mover) { map.removeAnimation(mover.animation); this.mover= null; }
function Map_distance(a,b){ var dx= Math.abs(a.x-b.x); var dy= Math.abs(a.y-b.y); var dist= dx>dy?dx:dy; return dist; };
function Map_clear() { var len= this.animations.length; for(var i=0; i<len; ++i) { if(this.animations[i]) { this.animations[i].end(); this.animations[i]= null; } } }
function Map_setMap(mapRaw) { this.ymax= mapRaw.length; this.xmax= mapRaw[0].length; this.map= mapRaw; }
function Map(mapRaw) { this.animations= new Array(); this.mapHasChanged= true; this.buffer=0;
//methods this.scan= Map_scan; this.getXYCode= getXYCode; this.setXYCode= setXYCode; this.addAnimation= Map_addAnimation; this.cleanAnimations= Map_cleanAnimations; this.removeAnimation= Map_removeAnimation; this.distance= Map_distance; this.clear= Map_clear;
this.setMap= Map_setMap; if(mapRaw) { this.setMap(mapRaw); } }
function readMap(mapPre) { var mapRaw=new Array();
//IE and gecko: var lines= mapPre.match(/.*/g); //opera is funny and divides the lines by whitespace var lines= mapPre.match(/S*s*/g);
var y=0; for(var yy=0, ylen=lines.length;yy<ylen;++yy) { //debugMsg("line("+(lines[yy].length)+"):"+lines[yy]); if(lines[yy].length>2){ var mapLine= new Array(); theLine= lines[yy]; var x=0; for(var xx=0, xlen=theLine.length;xx<xlen;++xx) { var thechar= theLine.charAt(xx); if(thechar!='n' && thechar!='r' && thechar>' ') { mapLine[x]= thechar; ++x; } } mapRaw[y]= mapLine; ++y; } }
var map= new Map(mapRaw); return map; }
function GameState_isFillable(pos){ var x= pos.x/step_unit; var y= pos.y/step_unit; if(x<0||y<0||x>=map.xmax||y>=map.ymax) return false; var code= map.getXYCode(x,y); switch(code) { case 'A': case '_': case ' ': return true; break; default: return false; } }
function GameState_pushTo(pos,from) { var two= new Coordinate(pos.x,pos.y); var step= step_unit;
var angle= Math.atan2(-(pos.y-from.y), pos.x-from.x); var direction= (180*angle/Math.PI+360)%360;
if(direction>=0 && direction<=45) two.x+= step; else if(direction>=45 && direction<=135) two.y-= step; else if(direction>=135 && direction<=225) two.x-= step; else if(direction>=225 && direction<=315) two.y+= step; else if(direction>=315 && direction<=360) this.image= basename+"_right.gif"; else debugMsg("pushTo bug:"+pos+" "+from);
// if(from.x<pos.x) { // two.x+= step; // } else if(from.x>pos.x) { // two.x-= step; // } else if(from.y<pos.y) { // two.y+= step; // } else if(from.y>pos.y) { // two.y-= step; // } return two; }
function pos_update(pos) { //debugMsg("updating to pos:"+pos.toString()); this.pos= pos; }
function Bullet_finish() { if(!this.hit) { //wimp rules: //return unused bullet to protagonist protagonist.bullets++; } gameState.removeBullet(this); }
function Mover_finish() { gameState.removeMover(this); map.setXYCode(toGridX(this.pos.x),toGridY(this.pos.y),this.avatar); }
//FIXME: this bullets stuff needs to be rewritten for an action game function CoordinateVector(pos,direction,steps) { this.direction= direction; this.dx= Math.cos(Math.PI*direction/180.0); this.dy= -Math.sin(Math.PI*direction/180.0); this.x= Math.floor(pos.x+this.dx*steps+fudge); this.y= Math.floor(pos.y+this.dy*steps+fudge); this.toString= Coordinate_toString; }
function Mover(source,destination,avatar,from) { this.source= source; this.pos= source; this.destination= destination; //FIXME: superfluous:pushed from: this.from=from;
//methods this.update= pos_update; this.finish= Mover_finish; this.avatar= avatar; }
function Bullet(pos,direction,steps) { this.source= pos; this.pos= pos; this.destination= new CoordinateVector(pos,direction,steps); this.direction= (direction+360)%360;
//methods this.update= pos_update; this.finish= Bullet_finish;
if(this.direction>=0 && this.direction<=45) this.avatar= bullet_right; else if(this.direction>=45 && this.direction<=135) this.avatar= bullet_up; else if(this.direction>=135 && this.direction<=225) this.avatar= bullet_left; else if(this.direction>=225 && this.direction<=315) this.avatar= bullet_down; else if(this.direction>=315 && this.direction<=360) this.avatar= bullet_right; else { this.avatar='fuck up('+this.direction+', bad argument)'; debugMsg(this.avatar); } }
function Attack_finish(animation) { map.removeAnimation(this.animation); // The following code was for giving the home precedence over attacks // Winners are immortal if(!gameState.victory) { protagonist.die(); } else { protagonist.freeze= false; } }
//Well, I try to avoid the super() constructor, since so far I made it without prototypes.. function Attack_init(that,code,source,destination) { that.source= source; that.pos= source; that.destination= destination;
var angle= Math.atan2(-(destination.y-source.y), destination.x-source.x); that.direction= (180*angle/Math.PI+360)%360;
//methods that.update= pos_update; that.finish= Attack_finish; }
function Attack(code,source,destination) { Attack_init(this,code,source,destination); switch(code) { case 'R': case 'S': case 'T': case 'U':
case 'r': case 's': case 't': case 'u': this.avatar= getBirdForDirection(this.direction); break;
case 'P': case 'p':
case 'P.right': case 'p.right': this.avatar= getSirenForDirection(this.direction); break;
default: debugMsg("unknown attacker "+code); this.avatar="unknown attacker"; }
}
function GameState_hitBullet(bullet,pos) { bullet.hit= true; gameState.removeBullet(bullet);
var x= toGridX(pos.x); var y= toGridY(pos.y); var code= map.getXYCode(x,y);
if(shrink) { map.addAnimation( new Animation( new Snapshot(code,pos,1.0,gameState.time), new Snapshot(' ',pos,0.0,gameState.time+1.0*ticks_unit) ) ); }
map.setXYCode(x,y,' '); return true; }
function GameState_checkBullet(bullet) {
var x= toGridX(bullet.pos.x); var y= toGridY(bullet.pos.y); var code= map.getXYCode(x,y);
//debugMsg("comparing x"+bullet.pos.x+" to x:"+x*step_unit);
//FIXME: this should be 0.5 or 0.05 instead of 0.40, but.. var target= new Coordinate(x*step_unit,y*step_unit);
// FIXME: sometimes bullets don't hit // debugMsg("bullet at "+bullet.pos+ // "target at "+target+ // "distance"+map.distance(bullet.pos,target));
if( map.distance(bullet.pos,target) > 0.40*step_unit ){ return false; }
switch(code) { case 'Z': case '[': case 'g': case 'C': return this.hitBullet(bullet,target); break; default: var absorbed= !this.isPassable(bullet.pos,bullet.source,"bullet"); if(absorbed) gameState.removeBullet(bullet); return absorbed; } }
function GameState_checkBullets(bullet) { if( this.bullet!= null ) { this.checkBullet(this.bullet); } }
function GameState_isPassable(pos,from,by){ var x= pos.x/step_unit; var y= pos.y/step_unit; var code= map.getXYCode(x,y);
switch(code) { case 'H': return gameState.home; case 'A': case '_': case ' ': return true; break;
case 'I': case 'J': case 'K': case 'i': case 'j': case 'k': return by=="protagonist"; break; case 'g': return this.color!="green"; break; case 'C': return this.color!="red"; break; case 'M': case 'N': case 'O': case 'P': return false; break; case 'R': case 'S': case 'T': case 'U': return false; break; case 'Z': case '[': return false; break; case 'L': return by=="protagonist" && this.isFillable(this.pushTo(pos,from)); break; case 'l': return false; default: debugMsg("isPassable: unknown tile code:"+code); return false;
} }
function GameState_beginEnter(pos,from){ var x= toGridX(pos.x); var y= toGridY(pos.y); var code= map.getXYCode(x,y);
switch(code) { case 'H': //this.victory= true; break; case 'A': case '_': case ' ': break; case 'I': case 'J': case 'K': if(shrink) { map.addAnimation( new Animation( new Snapshot(code,pos,1.0,gameState.time), new Snapshot(' ',pos,0.0,gameState.time+1.0*ticks_unit) ) ); } map.setXYCode(x,y,code.toLowerCase()); break; case 'g': break; case 'C': break; case 'M': case 'N': case 'O': case 'P': break; case 'R': case 'S': case 'T': case 'U': break; case 'Z': case '[': break; case 'L': var destination= gameState.pushTo(pos,from); // place dummy map.setXYCode(toGridX(destination.x),toGridY(destination.y),'l'); //empty tile map.setXYCode(x,y,' '); //begin animation var range= 1; var mover= new Mover(pos,destination,code,from); var animation= new Animation( new Snapshot(mover.avatar,mover.source,1.0,gameState.time), new Snapshot(mover.avatar,mover.destination,1.0,gameState.time+range*ticks_unit), mover );
mover.animation= animation; gameState.addMover(mover);
break; default: debugMsg("beginEnter: unknown tile code:"+code); } }
function removeBall(code,x,y) { gameState.sirens= true; map.setXYCode(x,y,' '); }
function GameState_finishEnter(pos,from){ var x= toGridX(pos.x); var y= toGridY(pos.y); var code= map.getXYCode(x,y);
switch(code) { case 'H': if(!protagonist.freeze) { this.victory= true; protagonist.setMode("victorious"); } break; case 'A': case '_': case ' ': break; case 'I': case 'J': case 'K': break; case 'i': removeBall(code,x,y); protagonist.bullets++; break; case 'j': this.color="green"; removeBall(code,x,y); break; case 'k': this.color="red"; removeBall(code,x,y); break; case 'g': break; case 'C': break; case 'M': case 'N': case 'O': case 'P': break; case 'R': case 'S': case 'T': case 'U': break; case 'Z': case '[': break; case 'L','l': //stop animation //rest on new tile break; default: debugMsg("finishEnter: unknown tile code:"+code); } }
function GameState_filterCode(code,x,y) { switch(code) { case 'H': if(this.home) code= code.toLowerCase(); break; case 'g': if( this.color!="green") code=' '; break; case 'C': if( this.color!="red") code=' '; break; case 'P': if(this.sirens) { code= code.toLowerCase(); //FIXME: bug is: map has to change to cause redraw, so a second map is needed .. if(protagonist.pos.x>x) { code+= '.right'; } } break; case 'R': case 'S': case 'T': case 'U': if(this.birds) code= code.toLowerCase(); break; case 'i': case 'j': case 'k': code=' '; break; case 'l': code=' '; break; }
return code; }
function GameState_mayShoot(){ return this.bullet==null; }
function GameState_checkTriggers() { //TODO: check if one has to check for i,j,k too if(!map.scan('I')&&!map.scan('J')&&!map.scan('K')) { this.birds= true; this.home= true; } else { this.birds= false; this.home= false; } }
//trap functions
//currently there is only one type of ray function checkForObstacle(code,pos) { //hack to disallow rays pushing var result=!gameState.isPassable(pos,pos,"ray"); return result; }
function checkForTarget(code,pos,source) { var hit= map.distance(protagonist.pos, pos)<=step_unit/2; if(hit) { protagonist.freeze= true; // start kill animation //empty tile map.setXYCode(x,y,' '); //begin animation var range= Math.floor(map.distance(source,protagonist.pos)/(2*step_unit))+1; var mover= new Attack(code,source,protagonist.pos); var animation= new Animation( new Snapshot(mover.avatar,mover.source,1.0,gameState.time), new Snapshot(mover.avatar,mover.destination,1.0,gameState.time+range*ticks_unit), mover );
mover.animation= animation; map.addAnimation(mover.animation); } return hit; }
function checkTrap(code,direction,checkForObstacle,checkForTarget) { var pos= null; while( pos= map.scan(code,pos) ) { //debugMsg("checking trap "+code+" at "+pos); scanTrap(code,direction,pos,checkForObstacle,checkForTarget); } }
function checkTraps() { //debugMsg("BEGIN checkTraps"); if(this.birds) { checkTrap('R',180,checkForObstacle,checkForTarget); checkTrap('S',90,checkForObstacle,checkForTarget); checkTrap('T',0,checkForObstacle,checkForTarget); checkTrap('U',270,checkForObstacle,checkForTarget); }
//debugMsg("end checkTraps birds");
if(this.sirens) { checkTrap('P',180,checkForObstacle,checkForTarget); checkTrap('P',90,checkForObstacle,checkForTarget); checkTrap('P',0,checkForObstacle,checkForTarget); checkTrap('P',270,checkForObstacle,checkForTarget); }
//debugMsg("end checkTraps sirens");
if(this.home) { var pos= map.scan(code_home); if(pos && map.distance(protagonist.pos, pos)<step_unit/3 && !protagonist.freeze ) { this.victory= true; protagonist.setMode("victorious"); } } //debugMsg("END checkTraps"); }
function GameState() { this.time= 0; this.color="green"; this.sirens= false; this.birds= false; this.home= false; this.victory= false; this.bullet= null; this.mover= null; //methods this.isPassable= GameState_isPassable; this.isFillable= GameState_isFillable; this.pushTo= GameState_pushTo; this.filterCode= GameState_filterCode;
this.beginEnter= GameState_beginEnter; this.finishEnter= GameState_finishEnter;
this.addBullet= GameState_addBullet; this.hitBullet= GameState_hitBullet; this.checkBullet= GameState_checkBullet; this.checkBullets= GameState_checkBullets; this.removeBullet= GameState_removeBullet; this.mayShoot= GameState_mayShoot;
this.addMover= GameState_addMover; this.removeMover= GameState_removeMover;
this.checkTriggers= GameState_checkTriggers; this.checkTraps= checkTraps; }
function Facings() { this.right= 0; this.left= 180; this.up= 90; this.down= 270; } var facings= new Facings();
var keybuffer= new Array();
var Agent_tick= function (ticks) {
//else used, so no diagonal movement allowed var nuarrived= true; var step= step_unit*ticks/ticks_unit; if(this.pos.x+step<=this.destination.x) { this.pos.x+= step; nuarrived= false; } else if(this.pos.x-step>=this.destination.x) { this.pos.x-= step; nuarrived= false; } else if(this.pos.y+step<=this.destination.y) { this.pos.y+= step; nuarrived= false; } else if(this.pos.y-step>=this.destination.y) { this.pos.y-= step; nuarrived= false; }
var togox= Math.abs(this.destination.x-this.pos.x)/step_unit; var togoy= Math.abs(this.destination.y-this.pos.y)/step_unit;
this.completion= 1.0-(togox>togoy?togox:togoy);
//debugMsg("Arrived:"+this.arrived+" "+(100*this.completion)+"% x:"+this.pos.x+" tox:"+this.destination.x+" y:"+this.pos.y+" toy:"+this.destination.y+" step="+step);
//process keys
//optional: read keyboard after 50% if(this.completion<0.5) { keybuffer= new Array(); }
//detect flank if(nuarrived & !this.arrived) { //optional: empty key buffer on arrival //keybuffer= new Array(); //debugMsg("finish enter "+this.destination.x+","+this.destination.y); gameState.finishEnter(this.destination,this.source); this.setMode(""); }
if(nuarrived && keybuffer.length>0 && !this.freeze) { var keyCode= keybuffer[0];
//optional:use key buffer if(keybuffer.shift) { keybuffer.shift(); } else keybuffer= new Array();
if (keyCode == key_right) { //r += 'arrow right'; this.destination.x= this.pos.x+step_unit; this.setFacing(facings.right); this.setMode("moving"); } else if (keyCode == key_down) { //r += 'arrow down'; this.destination.y= this.pos.y+step_unit; this.setFacing(facings.down); this.setMode("moving"); } else if (keyCode == key_up) { //r += 'arrow up'; this.destination.y= this.pos.y-step_unit; this.setFacing(facings.up); this.setMode("moving"); } else if (keyCode == key_left) { //r += 'arrow left'; this.destination.x= this.pos.x-step_unit; this.setFacing(facings.left); this.setMode("moving"); } else if (keyCode == key_fire) { // shoot if(this.bullets>0 && gameState.mayShoot() ) { var range= 2.44; var bullet= new Bullet(this.pos,this.facing,step_unit*range); var animation= new Animation( new Snapshot(bullet.avatar,bullet.source,1.0,gameState.time), new Snapshot(bullet.avatar,bullet.destination,1.0,gameState.time+range*ticks_unit), bullet );
bullet.animation= animation; gameState.addBullet(bullet); this.bullets--; } }
this.destination.clip(); if( !gameState.isPassable(this.destination,this.pos,"protagonist") ) { this.destination.x= this.pos.x; this.destination.y= this.pos.y; }else { this.source.x= this.pos.x; this.source.y= this.pos.y;
//fixme //this should not be needed //this.destination.gridLock(); //this.pos.gridLock(); gameState.beginEnter(this.destination,this.pos); } }
this.arrived= nuarrived; }
function Agent_setFacing(direction) { if(this.facing!=direction) { this.facing= direction; this.hasChanged= true; } }
function Agent_setMode(mode) { if(this.mode!=mode) { this.mode= mode; this.hasChanged= true; } }
function Agent_init(agent,name,x,y) { agent.name= name; agent.buffer= 0;
agent.source= new Coordinate(x,y); agent.pos= new Coordinate(x,y); agent.destination= new Coordinate(x,y);
agent.arrived= true; agent.completion= 1.0; agent.hasChanged= true;
agent.facing= 0;//right //methods agent.tick= Agent_tick; agent.setFacing= Agent_setFacing; agent.setMode= Agent_setMode; }
function Agent(name,x,y) { Agent_init(this, name, x ,y); }
// function mapFromTemplate(map,initializer) { // var tis= new Array(map.length); // for(var y=0;y<tis.length;++y) { // tis[y]= new Array(map[y].length); // for(var x=0;x<tis[y].length;++x) { // tis[y][x]= initializer; // } // } // return tis; // }
// // Please don't much use browser detection, only for final polish // function setBrowser() { if( navigator.appName=="Microsoft Internet Explorer" ) {
debugMsg("like IE!");// or opera or any faker .. browsercaps.doublebuffer= true;
//this is for IE, not opera FIXME! //IE is very slow with fixed and divs and scrolls anyway //Actually it seems IE is slow with big windows var wrapper= document.getElementById("mapwrapper"); if(wrapper&&wrapper.style&&wrapper.style.position) { wrapper.style.position=""; } }
if( navigator.product=="Gecko" ) { debugMsg("like Gecko!"); // switch on HTML normalization to avoid flicker. browsercaps.fixHTML= true; } }
function preload() { var dummy= new Agent("dummy",0,0); dummy.mapToImage= Protagonist_mapToImage;
dummy.setFacing(0); dummy.setMode("victorious"); loadImages( imagePath(dummy.mapToImage() ) ); dummy.setMode(""); loadImages( imagePath(dummy.mapToImage() ) ); dummy.setMode("moving"); loadImages( imagePath(dummy.mapToImage() ) ); dummy.setFacing(90); dummy.setMode(""); loadImages( imagePath(dummy.mapToImage() ) ); dummy.setMode("moving"); loadImages( imagePath(dummy.mapToImage() ) ); dummy.setFacing(180); dummy.setMode(""); loadImages( imagePath(dummy.mapToImage() ) ); dummy.setMode("moving"); loadImages( imagePath(dummy.mapToImage() ) ); dummy.setFacing(270); dummy.setMode(""); loadImages( imagePath(dummy.mapToImage() ) ); dummy.setMode("moving"); loadImages( imagePath(dummy.mapToImage() ) );
// only loading what can appear later loadImages( mapCodeToImage('h') );
loadImages( mapCodeToImage('r') ); loadImages( mapCodeToImage('s') ); loadImages( mapCodeToImage('t') ); loadImages( mapCodeToImage('u') );
loadImages( mapCodeToImage(bird_right) ); loadImages( mapCodeToImage(bird_down) ); loadImages( mapCodeToImage(bird_left) ); loadImages( mapCodeToImage(bird_up) );
loadImages( mapCodeToImage('P') ); loadImages( mapCodeToImage('p') ); loadImages( mapCodeToImage('P.right') ); loadImages( mapCodeToImage('p.right') ); loadImages( mapCodeToImage('p.moving.left') ); loadImages( mapCodeToImage('p.moving.up') ); loadImages( mapCodeToImage('p.moving.down') ); loadImages( mapCodeToImage('p.moving.right') );
loadImages( mapCodeToImage('g') ); loadImages( mapCodeToImage('C') );
loadImages( mapCodeToImage('bullet_big' ) ); loadImages( mapCodeToImage( bullet_right ) ); loadImages( mapCodeToImage( bullet_up ) ); loadImages( mapCodeToImage( bullet_left ) ); loadImages( mapCodeToImage( bullet_down ) );
debugMsg("commanded preloading of "+myImages.length+" images"); }
function Protagonist_die() { this.shrink= true; if(typeof this.zoom!='number') { this.zoom= 1.0; } }
function Protagonist_tick(ticks) { //well, I worked without prototypes so far, I'm not going to start it now //this.prototype.tick(ticks) if(this.shrink) { this.zoom-= ticks/ticks_unit; this.hasChanged= true; } }
function Protagonist(ppos) { Agent_init(this,"protagonist",ppos.x,ppos.y); this.draw= Protagonist_draw; this.bullets=0; this.mapToImage= Protagonist_mapToImage; this.freeze= false; this.die= Protagonist_die; this.zoom= null; this.shrink= false; this.ptick= Protagonist_tick; }
function resetGameState() { gameState= new GameState();
var ppos= map.scan(code_start); if(!ppos) { alert("this map lacks a starting position"); ppos= new Coordinate(0,0); }
protagonist= new Protagonist(ppos); }
function layout2(left) { var div; //controls var div= document.getElementById("controls"); div.style.top= 20; div.style.left= left; //scratchpad var div= document.getElementById("help"); div.style.top= 150; div.style.left= left;
var div= document.getElementById("by"); div.style.top= 210; div.style.left= left;
var div= document.getElementById("sp0"); div.style.top= 360; div.style.left= left+300;
//debug var div= document.getElementById("debug"); div.style.left= left;
}
function resizeDiv(name,width,height) { var div= document.getElementById(name); if(div && div.style) { div.style.width= width; div.style.height= height; } }
function configure() { var search= window.location.search;
if( search.match(/debug=1/) ){ debug= true; hideDebug= false; }
if( search.match(/shrink=0/) ){ shrink= false; }
if( search.match(/size=32/) ){ map_left= 20; cell_width= 32; cell_height= 32; setTimeout("layout2("+(cell_width*12+20+map_left)+")",1); if(!debug) { resizeDiv("mapwrapper",1000-206,580-170); } }
if( search.match(/size=48/) ){ cell_width= 48; cell_height= 48; setTimeout("layout2("+(cell_width*12+28+map_left)+")",1); resizeDiv("mapwrapper",1000,580-20); }
if( search.match(/size=64/) ){ cell_width= 64; cell_height= 64; setTimeout("layout2("+(cell_width*12+28+map_left)+")",1); resizeDiv("mapwrapper",1000+210,580+100); }
var debugDiv= document.getElementById("debugoutput"); debugDiv.style.visibility= debug?'visible':'hidden';
var debugonoffDiv= document.getElementById("debugonoff"); debugonoffDiv.style.visibility= (!hideDebug)?'visible':'hidden'; }
function resizeStatusbar(map){ var statusDiv= document.getElementById("status"); var width= (map.xmax)*cell_width; if(width<minStatusbarWidth) width= minStatusbarWidth; if(statusDiv && statusDiv.style) { statusDiv.style.width= width; } var height= bullet_height>status_font?bullet_height:status_font; statusDiv.style.height= height; statusDiv.style.top= map_top-height; }
function resetGUI() { resizeStatusbar(map); var mapObjO= document.getElementById("map"+0); if(mapObjO) { mapObjO.innerHTML=""; } var mapObjN= document.getElementById("map"+1); if(mapObjN) { mapObjN.innerHTML=""; } keybuffer= new Array(); scroll(0,0); window.focus(); }
function init() {
configure();
//The code is supposed to work in all browsers, but we can improve performance sometimes if we know browser setBrowser(); preload(); placeMap(); drawStatusBullets(); loadSetIndex();
map= new Map(mapRaw); resetGameState(); resetGUI();
setTimeout("loadNextMap()",4999);
mainLoop();
}
function mainLoop() { if(mainProceed) {
protagonist.tick(theTick); protagonist.ptick(theTick); gameState.time+=theTick;
drawMap();
drawAnimations(); map.cleanAnimations(gameState.time); gameState.checkBullets();
if(gameState.time%ticks_unit<theTick) { gameState.checkTriggers(); //FIXME: the tiles affected by traps should be marked, //so that processing is faster gameState.checkTraps(); }
if(gameState.time%(ticks_unit/3)<theTick) { drawStatus(); } //drawMap();//FIXME: This takes too long e.g. push box protagonist.draw(); } setTimeout("mainLoop()",mainDelay); }
function drawAnimations() { for(var i=0;i<map.animations.length;++i) { if(map.animations[i]) { map.animations[i].animate(gameState.time); } } }
var hashImages= new Array();
function imageFor(imgsrc,title,height,width,id) { var key= imgsrc+" "+title+" "+height+" "+width; var fullkey= key+" "+id;
saved= hashImages[fullkey]; if(saved) { return saved; }
saved= hashImages[key]; if(saved) { saved= saved.cloneNode(false); hashImages[fullkey]= saved; return saved; }
var img= document.createElement("IMG"); img.setAttribute("src",imgsrc); img.setAttribute("alt",title); img.setAttribute("title",title); img.setAttribute("height",""+height); img.setAttribute("width",""+width); img.setAttribute("style","margin: 0px 0px 0px 0px;"); img.setAttribute("border","0");
hashImages[key]= img; hashImages[fullkey]= img;
return img; }
function mapCodeToNode(code,width,height,forId) { var node= null; var imgsrc= mapCodeToImage(code); if(imgsrc) { node= imageFor(imgsrc,code,height,width,forId); } else { var box=""; switch( code ){ case '_': case ' ': case 'A': box= " "; break; default: box= " "+code+" "; } node= document.createElement("SPAN"); node.innerHTML= box; } return node; }
function clearChildren(node) { while(node.firstChild != null ) { node.removeChild(node.firstChild); } }
function makeMap() {
var text="";
text+='<table border=0 cellpadding=0 cellspacing=0 style="background-image:url(''+mapCodeToImage("background")+'')">'; var tr= "<tr height="+cell_height+">"; var td= "<td class=map width="+cell_width+">";
for(y=0;y<map.ymax;++y) { text+= tr; for(x=0;x<map.xmax;++x) { text+= td;
var code= map.map[y][x];
code= gameState.filterCode(code,x*step_unit,y*step_unit);
var box= mapCodeToHtml(code,cell_width,cell_height);
text+= box; text+="</td>"; } text+="</tr>"; } text+="</table>";
return text; }
function placeMap(){ var mapObjO= document.getElementById("map0"); mapObjO.style.left=map_left; mapObjO.style.top=map_top;
var mapObjN= document.getElementById("map1"); mapObjN.style.left=map_left; mapObjN.style.top=map_top;
var mapObjO= document.getElementById("status"); mapObjO.style.left=map_left; }
function drawMap() { if(map.mapHasChanged) { map.mapHasChanged=false;
var starttime; if(debug && debugall) { starttime= new Date(); }
if( browsercaps.doublebuffer ) { //Opera and IE seem to double buffer anyway var mapObjO= document.getElementById("map"+map.buffer); mapObjO.innerHTML= makeMap(); }else{ //doublebuffering for Gecko/FireFox var mapObjO= document.getElementById("map"+map.buffer); map.buffer^=1; var mapObjN= document.getElementById("map"+map.buffer); mapObjN.style.zIndex=0;
mapObjN.innerHTML= makeMap(); mapObjO.style.zIndex=5; mapObjN.style.zIndex=10; mapObjO.style.zIndex=0; }
if(debug && debugall) { var endtime= new Date(); debugMsg("redrawing map took "+(endtime-starttime)+"ms"); }
}// map has changed
}
function Protagonist_draw() { var mapObjN= document.getElementById(this.name+this.buffer); //this.buffer= this.buffer^1; //var mapObjO= document.getElementById(this.name+this.buffer); var left= toScreenX(this.pos.x/step_unit); var top= toScreenY(this.pos.y/step_unit); //this redraw often isn't necessary => don't redraw if(this.hasChanged) { this.hasChanged= false; //FIXME: protagonist width and height are a hack var width= cell_width; var height= cell_height;
if((typeof this.zoom)=='number') { zwidth= Math.floor(width*this.zoom+fudge); zheight= Math.floor(height*this.zoom+fudge); left+= Math.floor((width-zwidth)/2); top+= Math.floor((height-zheight)/2); width= zwidth; height= zheight; }
var text; if(width<1||height<1) { text=''; this.shrink= false; } else { text= '<img src="'+imagePath(protagonist.mapToImage())+'" alt="@" border="0" height="'+Math.floor(height)+'" width="'+Math.floor(width)+'" style="margin:0px;">'; } mapObjN.innerHTML= text; }
mapObjN.style.left= left; mapObjN.style.top= top;
//mapObjO.style.visibility="hidden"; //mapObjN.style.visibility="visible"; }
function checkArrows (field, evt) { var keyCode = document.layers ? evt.which : document.all ? event.keyCode : document.getElementById ? evt.keyCode : 0;
var r = ''; if (keyCode == 39 || keyCode == 57388 || String.fromCharCode(keyCode).toLowerCase()=='d') { r += 'arrow right'; keyCode = key_right; } else if (keyCode == 40 || keyCode == 57386 || String.fromCharCode(keyCode).toLowerCase()=='s') { r += 'arrow down'; keyCode = key_down; } else if (keyCode == 38 || keyCode == 57385 || String.fromCharCode(keyCode).toLowerCase()=='w') { r += 'arrow up'; keyCode = key_up; } else if (keyCode == 37 || keyCode == 57387 || String.fromCharCode(keyCode).toLowerCase()=='a') { r += 'arrow left'; keyCode = key_left; } else if( keyCode == 220 || keyCode == 49 || keyCode== 70 || keyCode== 81 || keyCode== 45) { //^1FQ0 r += 'action key 1'; keyCode = key_fire; } else if( String.fromCharCode(keyCode).toLowerCase() == 'r' ) { //r r += 'reload'; loadFrom(lastLevel); }
if(r!='') { if(keybuffer.push) { keybuffer.push(keyCode); }else{ keybuffer[keybuffer.length]= keyCode; }
//I don't manage to intercept keyboad events .. //scroll(0,0); return true; }
// var whichChar=String.fromCharCode(keyCode); r += ' ' + keyCode; if(debug) { window.status = r; } return false; }
function focusOn(name) { var div= document.getElementById(name); if(div && div.focus) { div.focus(); } }
var focus_restart= false;
var bullets_number= 10;
// some versions of IE don't like loading many images, so we keep some static bullets
function drawStatusBullets() { var statusDiv= document.getElementById("status"); text=""; var x= 0; for(var i=0; i< bullets_number; ++i) { text+= '<div id="statusbullet'+i+'" style="position:absolute; left:'+x+'; z-index:16; visibility:hidden">'; text+= '<img src="'+mapCodeToImage("bullet_big")+'" alt="o" border="0" height="'+bullet_height+'" width="'+bullet_width+'">'; text+= '</div>'; x+= bullet_width; } text+= '<div id="statustext" style="position: absolute; z-index:17;"> </div>';
statusDiv.innerHTML= text; }
var last_show_bullets= -1; function drawStatus() { var statusDiv= document.getElementById("status"); var statustextDiv= document.getElementById("statustext");
var text="";
var show_bullets= protagonist.bullets;
if(gameState.victory) { text='<b style="color: rgb(127, 255, 127);">You won!</b>'; show_bullets= 0; } else if(protagonist.freeze) { text='<b style="color: red;">You loose! Failure lifts its ugly head.<a href="javascript:loadFrom(lastLevel);">restart!</a></b>'; show_bullets= 0; if(!focus_restart) { focusOn("restart"); focus_restart= true; } }
if(show_bullets==0 && text=="") { statusDiv.style.visibility= 'hidden'; } else { statusDiv.style.visibility= 'visible'; }
if(show_bullets!=last_show_bullets) { last_show_bullets= show_bullets; for(var i=0;i<bullets_number;++i) { var bulletDiv= document.getElementById("statusbullet"+i); var visibility= i<show_bullets?'visible':'hidden'; if(visibility!=bulletDiv.style.visibility) { bulletDiv.style.visibility= visibility; bulletDiv.style.zIndex= 16; } } } if(show_bullets>bullets_number) { text= '<b>'+show_bullets+'</b>'; }
//uncomment this or fix html manually to stop flickering if(text!=statustextDiv.innerHTML) { //debug flickering if(debug && debugall) { debugHTMLrep(text); } statustextDiv.innerHTML= text; } }
// // loading levels //
function loadFrom(url){ focus_restart= false; var scratchpadFrame= document.getElementById("scratchpadFrame"); scratchpadFrame.src= url+'?'+Math.floor(Math.random()*1000000); }
// //fix IE mangled select values(remove trailing spaces) // function fixIE(value){ if(value) { while( value.charCodeAt(value.length-1)<=32 ) { value= value.substr(0,value.length-1); } } return value; }
var levelSet= null;
function gotSets(setNames) { var setSelect= document.getElementById("setname"); var options= setSelect.options; while(options.length>1) setSelect.remove(1); // var anOption = document.createElement("OPTION") // anOption.text = "--choose--"; // anOption.value = ""; // options.add(anOption); for(var i=0; i<setNames.length; ++i) { var anOption = document.createElement("OPTION") anOption.text = setNames[i]; anOption.value = setNames[i]; options.add(anOption); } }
function gotLevels(levelNames) { var levelSelect= document.getElementById("levelname"); var options= levelSelect.options; while(options.length>1) levelSelect.remove(1); for(var i=0; i<levelNames.length; ++i) { var anOption = document.createElement("OPTION") anOption.text = levelNames[i]; anOption.value = "maps/"+levelSet+"/"+fixIE(levelNames[i])+'.html'; options.add(anOption); } }
// // FIXME: some browser might require fiddling with selectedIndex //
function loadSetIndex() { loadFrom("maps/list.html"); }
function loadSet(setInput) { var value= fixIE(setInput.value); if(value) { loadFrom("maps/"+value+"/list.html"); levelSet= value; setInput.blur(); } }
function loadLevel(levelInput) { var level= fixIE(levelInput.value); if(level) { lastLevel= level; loadFrom(level); levelInput.blur(); } }
function loadNextMap(){ var levelSelect= document.getElementById("levelname"); var levelOptions= levelSelect.options; var selected= levelOptions.selectedIndex; ++selected; if( selected>=levelOptions.length ){ var setSelect= document.getElementById("setname"); var setOptions= setSelect.options; var selected= setOptions.selectedIndex; ++selected; setOptions.selectedIndex= selected>=setOptions.length?1:selected; loadSet(setSelect); setTimeout("loadNextMap()",1999); }else{ levelOptions.selectedIndex= selected; loadLevel(levelSelect); } }
function killBill(fileName) { return fileName.replace(/\/gi,"/"); }
function loadFileFromFileinput(fileInput) { var fileName=fileInput.value; debugMsg("loading file:"+fileName); if(fileName) { fileName= "file:///"+killBill(fileName); loadFrom(fileName); fileInput.blur(); return true; }else { return false; } }
function loadFileFromUrlinput(urlInput) { var fileName=urlInput.value; debugMsg("loading url:"+fileName); if(fileName) { if(!fileName.match(/^http:/) ) { fileName= "http://"+fileName; } loadFrom(fileName); urlInput.blur(); return true; }else { return false; } }
function loadFileFromForm(form) { // if(! loadFileFromFileinput(form.filename) ) { // if(! loadFileFromUrlinput(form.url) ) loadLevel(form.levelname); // } form.load.blur(); }
function loadFileFromFormname(formname) { loadFileFromForm(document[formname]); }
function gotMaps(newMapsPre) { //only the first map is used currently if(newMapsPre.length>0) { if(map) { map.clear(); } map= readMap(newMapsPre[0]); resetGameState(); resetGUI(); } }
//code graveyard, usefull stuff that I don't know by heart
// document.body.addEventListener("keydown", processKeypress, true);
// code sample //for (prop in scratchpadFrame) { // debugMsg(prop+":"+scratchpadFrame[prop]); //} //
// code sample, adding event listeners // function addEvent(obj, evType, fn){ // if (obj.addEventListener){ // obj.addEventListener(evType, fn, true); // return true; // } else if (obj.attachEvent){ // var r = obj.attachEvent("on"+evType, fn); // return r; // } else { // return false; // } // }
//--> </script>
<!-- bgsound --> <script language="JavaScript" type="text/JavaScript"><!-- // See also: http://www.ricocheting.com/js/music.html // var music="gayatri.mp3"; // if(navigator.product=="Gecko"){ // document.write('<embed src="'+music+'" autostart="true" loop="true" controls="SmallConsole" width=145 height=15></embed>');} // else if(navigator.appName=="Microsoft Internet Explorer"){ // document.write('<embed src="'+music+'" autostart="true" loop="true" width=285 height=25></embed>');} // else{ // document.write('<embed src="'+music+'" autostart="true" loop="true"></embed>');} // //--> // </script> <!--noscript><embed src="gayatri.mp3" autostart="true" loop="true"></embed></noscript> <noembed><bgsound src="gayatri.mp3" loop=true></noembed-->
</head> <body onLoad="init();" onKeyDown="checkArrows(this,event)" style="margin: 0px 0px 0px 0px; padding: 0px 0px 0px 0px;"> <!-- FIXME: this fixed div(against scrolling) makes IE 5 incredibly slow --> <div id="mapwrapper" style="position:fixed; top:0px; left:0px; height:400px; width:794px; overflow:hidden; background:#aa9988">
<!--begin screen--> <div id="map0" style="position:absolute; z-index:10"> </div> <div id="map1" style="position:absolute; z-index:10"> </div> <div id="status" style="position:absolute; left:20px; width:384px; height:12px; z-index:15; background: rgb(0, 0, 127); visibility: hidden;" class="map"> </div> <div id="protagonist0" style="position:absolute; z-index:20"> </div> <div id="protagonist1" style="position:absolute; z-index:20; visibility:hidden;"> </div>
<div id="animation0" style="position:absolute; z-index:40; visibility:hidden;"></div> <div id="animation1" style="position:absolute; z-index:40; visibility:hidden;"></div> <div id="animation2" style="position:absolute; z-index:40; visibility:hidden;"></div> <div id="animation3" style="position:absolute; z-index:40; visibility:hidden;"></div> <div id="animation4" style="position:absolute; z-index:40; visibility:hidden;"></div> <div id="animation5" style="position:absolute; z-index:40; visibility:hidden;"></div> <div id="animation6" style="position:absolute; z-index:40; visibility:hidden;"></div> <div id="animation7" style="position:absolute; z-index:40; visibility:hidden;"></div> <div id="animation8" style="position:absolute; z-index:40; visibility:hidden;"></div> <div id="animation9" style="position:absolute; z-index:40; visibility:hidden;"></div>
<div id="help" style="position:absolute;left:40px;width:320px;top:350px;"> <center> Use the arrow keys to move. Also try "awds"-keys. <br> 0,Q,F,1, or ^ shoots a bullet. R is restart. <A href="index.html" target="help">Help!</A> </center> </div>
<div id="by" style="position:absolute; left:452px; width:340px; top:150px;"> <center> <h3>HylZee</h3> game idea:<A href="http://www.huelsmann.net/">Roland G. Hülsmann</A> <br>javascript coding:<A href="mailto:peter.schafer@gmail.com">(c)2004 Peter Schäfer</A> <br>level design, set A:<A href="http://www.huelsmann.net/">Roland G. Hülsmann</A> <br>level design, set B:<A href="mailto:peter.schafer@gmail.com">Peter Schäfer</A> <br>Browsers tested: Opera7, IE5, FireFox 1.0 <br>This software is licensed under the GPL. </center> <p><!-- music --> </div>
<!--end screen-->
<div id="controls" style="position:absolute; z-index:10; left:452px; top:20px; width:440px; height:90px;"> <table border="0" class="controlembossed"> <tr><td>
<form name="form_controls" method="POST" enctype="multipart/form-data" style="margin:4px 4px 4px 4px" action="javascript:loadFileFromFormname('form_controls');"> <table border="0" style="background: #66CC33;"> <tr><td> level set: </td><td> <select id="setname" name="setname" OnChange="javascript:loadSet(this);return false;"> <option value="">-- choose --</option> <option value="B">B</option> </select> level <select id="levelname" name="levelname" OnChange="javascript:loadLevel(this);return false;"> <option value="">-- choose --</option> </select> <!-- </td></tr><tr><td> load url: </td><td> <input type=text name="url" OnChange="javascript:loadFileFromUrlinput(this);return false;"> </td></tr><tr><td> load file: </td><td> <input type=file name="filename" OnChange="javascript:loadFileFromFileinput(this);return false;"> --> </td></tr><tr><td align="center" colspan=2> <input type=button name="nextmap" value="next map" OnClick="javascript: loadNextMap();"> <input type=button id="restart" name="restart" value="restart last" OnClick="javascript:loadFrom(lastLevel);"> <input type=button name="load" value="load" OnClick="javascript:loadFileFromFormname('form_controls');"> <input type=reset value="reset" OnClick="javascript:return true;"> </td></tr> </table> </form>
</td></tr> </table> </div>
<!-- load data with javascript --> <!-- I have made this visible, since browsers might consider it bad security otherwise --> <div id=sp0 style="position:absolute; z-index:0; visibility:visible; top:350px; left:600px; height:40px; width:40px; overflow:hidden"> <iframe src="about:blank" id="scratchpadFrame" height="20" width="40"></iframe> <!-- scratchpad to convert innerHTML to browser representation --> <div id="scratchpad" style="position:absolute; z-index:0; visibility:visible; overflow: hidden;"></div> </div>
<div id="debug" style="position:absolute;left:452px;width:300px;"> <div id="debugonoff" style="position:absolute;width:300px;height:30px;top:155px; background:#EEEEEE; visibility: hidden;"> <center> <form action="javascript:return false;" style="margin: 0px;"> <input type=button value="debug on/off" OnClick="javascript:debug=!debug;document.getElementById('debugoutput').style.visibility='visible'; this.value='debug '+(debug?'off':'on')"> <input type=button value="clear" OnClick="javascript:document.getElementById('debug').innerHTML=''"> <input type=button value="proceed/stop" OnClick="javascript:mainProceed=!mainProceed;this.value=(mainProceed?'stop':'proceed')"> </form> </center> </div>
<div id="debugoutput" style="position:absolute; top:190px; width:300px; height:320px; overflow:auto; background:#EEEEEE; font-family: fixed; visibility: hidden;"> <h4>debug log</h4> </div> </div>
</div>
</body> </html>
|