jhylands

html 5 game

Mar 8th, 2013
232
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
HTML 5 49.59 KB | None | 0 0
  1.  
  2.  
  3. <!-- Main page for Stage One Maze by Sean McKean (check main.js for license) -->
  4.  
  5. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  6. <html xmlns="http://www.w3.org/1999/xhtml">
  7.  
  8. <head>
  9.     <meta http-equiv="X-UA-Compatible" content="chrome=1" />
  10.     <title>stage one maze</title>
  11.  
  12.     <style>
  13.         body {
  14.             text-align: center;
  15.             font: 100% monospace;
  16.             background-color: #fff;
  17.         }
  18.         canvas {
  19.             border: 1px solid black;
  20.         }
  21.     </style>
  22. </head>
  23.  
  24. <body>
  25.     <canvas id="mainCanvas" width="600" height="400">
  26.         canvas tag not supported by this browser.
  27.     </canvas>
  28.     <p>
  29.         <button id="edit">set up</button>&nbsp;
  30.         <button id="makeMaze" disabled>create maze</button>&nbsp;
  31.         show win display<input id="winCheck" type="checkbox" checked />&nbsp;
  32.         predefined sizes:
  33.         <select id="sizes" disabled>
  34.             <option value="custom">custom</option>
  35.             <option value="a" selected>5x5x5</option>
  36.             <option value="b">7x7x7</option>
  37.             <option value="c">9x9x9</option>
  38.             <option value="d">11x11x11</option>
  39.             <option value="e">13x13x13</option>
  40.             <option value="f">25x25x1</option>
  41.         </select>
  42.         <br />
  43.         <button id="instructions">instructions</button>&nbsp;
  44.         canvas size: <select id="canvasSizes" disabled>
  45.             <option value="a">small</option>
  46.             <option value="b" selected>medium</option>
  47.             <option value="c">large</option>
  48.             <option value="d">x-large</option>
  49.         </select>&nbsp;
  50.         width: <input id="width" type="text" size="3" value="5" disabled></input>&nbsp;
  51.         height: <input id="height" type="text" size="3" value="5" disabled></input>&nbsp;
  52.         depth: <input id="depth" type="text" size="3" value="5" disabled></input>
  53.     </p>
  54.     <div id="fpsText">
  55.         <p>Average FPS: <span id="fpsCount">0</span></p>
  56.     </div>
  57.     <br /><p><a href="http://systemsymmetry.com">Return to home page</a></p>
  58.  
  59.     <script type="text/javascript">/*
  60.  * Stage One Maze
  61.  * Copyright (c) 2012 Sean McKean (smckean AT systemsymmetry DOT com)
  62.  *
  63.  * Permission is hereby granted, free of charge, to any person obtaining a
  64.  * copy of this software and associated documentation files (the "Software"),
  65.  * to deal in the Software without restriction, including without limitation
  66.  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  67.  * and/or sell copies of the Software, and to permit persons to whom the
  68.  * Software is furnished to do so, subject to the following conditions:
  69.  *
  70.  * The above copyright notice and this permission notice shall be included
  71.  * in all copies or substantial portions of the Software.
  72.  *
  73.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  74.  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  75.  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  76.  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
  77.  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  78.  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  79.  * OTHER DEALINGS IN THE SOFTWARE.
  80.  */
  81.  
  82. var middleMouseTime;
  83.  
  84. function time() {
  85.     return new Date().getTime();
  86. }
  87.  
  88. function disableEvent(evt) {
  89.     evt.preventDefault();
  90. }
  91.  
  92. function mouseButtonPrecedence(i, j) {
  93.     return (mbstate[i] > 0 && (mbstate[i] < mbstate[j] || mbstate[j] == 0));
  94. }
  95.  
  96. function onMouseMove(evt) {
  97.     msx = evt.clientX;
  98.     msy = evt.clientY;
  99.     if(msx < 0)
  100.         msx = 0;
  101.     if(msx >= window.innerWidth)
  102.         msx = window.innerWidth-1;
  103.     if(msy < 0)
  104.         msy = 0;
  105.     if(msy >= window.innerHeight)
  106.         msy = window.innerHeight-1;
  107. }
  108.  
  109. function onMouseDown(evt) {
  110.     if(evt.button > 0 || msx < window.innerWidth-24) {
  111.         if(evt.button == 0) {
  112.             if(mbstate[1] == 0 || mouseButtonPrecedence(2, 1)) {
  113.                 plrSpeed = MaxSpeed/2;
  114.             } else {
  115.                 plrSpeed = 0.0;
  116.             }
  117.         }
  118.         for(var i = 0; i < 3; i++)
  119.             if(mbstate[i] > 0)
  120.                 mbstate[i]++;
  121.         mbstate[evt.button] = 1;
  122.         mbpos = { x: evt.clientX, y: evt.clientY };
  123.         if(evt.button == 1)
  124.             middleMouseTime = time();
  125.         evt.preventDefault();
  126.     }
  127. }
  128.  
  129. function onMouseUp(evt) {
  130.     if(evt.button == 0)
  131.         plrSpeed = 0.0;
  132.     if(evt.button == 1 && time()-middleMouseTime < 250)
  133.         keys.tab = true;
  134.     mbstate[evt.button] = 0;
  135.     for(var i = 0; i < 3; i++)
  136.         if(mbstate[i] > 1)
  137.             mbstate[i]--;
  138.     mbpos = { x: evt.clientX, y: evt.clientY };
  139.     evt.preventDefault();
  140. }
  141.  
  142. function onMouseScroll(evt) {
  143.     if(evt.wheelDelta > 0)
  144.         mapZoom = clip(mapZoom*MapZoomMult, 1.0, 16.0);
  145.     if(evt.wheelDelta < 0)
  146.         mapZoom = clip(mapZoom/MapZoomMult, 1.0, 16.0);
  147.     if(msx < window.innerWidth-24)
  148.         evt.preventDefault();
  149. }
  150.  
  151. function setKey(evt, name, value) {
  152.     keys[name] = value;
  153.     evt.preventDefault();
  154. }
  155.  
  156. function onKeyDown(evt) {
  157.     if(evt.which) {
  158.         key = evt.which;
  159.     } else if(window.event) {
  160.         key = evt.keyCode;
  161.     }
  162.     switch(key) {
  163.     case 83:  // Rotate down
  164.         setKey(evt, 's', 1);  break;
  165.     case 87:  // Rotate up
  166.         setKey(evt, 'w', 1);  break;
  167.     case 65:  // Rotate left
  168.         setKey(evt, 'a', 1);  break;
  169.     case 68:  // Rotate right
  170.         setKey(evt, 'd', 1);  break;
  171.     case 81:  // Roll left
  172.         setKey(evt, 'q', 1);  break;
  173.     case 69:  // Roll right
  174.         setKey(evt, 'e', 1);  break;
  175.     case 82:  // Move forward
  176.         setKey(evt, 'r', 1);  break;
  177.     case 70:  // Move backward
  178.         setKey(evt, 'f', 1);  break;
  179.     case 88:  // Strafe down
  180.         setKey(evt, 'x', 1);  break;
  181.     case 67:  // Strafe up
  182.         setKey(evt, 'c', 1);  break;
  183.     case 90:  // Strafe left
  184.         setKey(evt, 'z', 1);  break;
  185.     case 86:  // Strafe right
  186.         setKey(evt, 'v', 1);  break;
  187.     case 9:  // tab
  188.     case 77:  // 'm' -- toggle map
  189.         setKey(evt, 'tab', true);  break;
  190.     case 32:  // spacebar
  191.         setKey(evt, 'spc', true);  break;
  192.     case 188:  // ','
  193.     case 189:  // '-'
  194.         setKey(evt, 'minus', true);  break;
  195.     case 190:  // '.'
  196.     case 187:  // '='
  197.         setKey(evt, 'plus', true);  break;
  198.     }
  199.     //console.log(key);
  200. }
  201.  
  202. function onKeyUp(evt) {
  203.     if(evt.which) {
  204.         key = evt.which;
  205.     } else if(window.event) {
  206.         key = evt.keyCode;
  207.     }
  208.     switch(key) {
  209.     case 83:
  210.         setKey(evt, 's', 0);  break;
  211.     case 87:
  212.         setKey(evt, 'w', 0);  break;
  213.     case 65:
  214.         setKey(evt, 'a', 0);  break;
  215.     case 68:
  216.         setKey(evt, 'd', 0);  break;
  217.     case 81:
  218.         setKey(evt, 'q', 0);  break;
  219.     case 69:
  220.         setKey(evt, 'e', 0);  break;
  221.     case 82:
  222.         setKey(evt, 'r', 0);  break;
  223.     case 70:
  224.         setKey(evt, 'f', 0);  break;
  225.     case 88:
  226.         setKey(evt, 'x', 0);  break;
  227.     case 67:
  228.         setKey(evt, 'c', 0);  break;
  229.     case 90:
  230.         setKey(evt, 'z', 0);  break;
  231.     case 86:
  232.         setKey(evt, 'v', 0);  break;
  233.     }
  234. }
  235.  
  236. function changeWindowListeners(add) {
  237.     if(add) {
  238.         window.addEventListener('mousemove', onMouseMove, false);
  239.         window.addEventListener('mousedown', onMouseDown, false);
  240.         window.addEventListener('mouseup', onMouseUp, false);
  241.         window.addEventListener('mousewheel', onMouseScroll, false);
  242.         window.addEventListener('keydown', onKeyDown, false);
  243.         window.addEventListener('keyup', onKeyUp, false);
  244.     } else {
  245.         window.removeEventListener('mousemove', onMouseMove, false);
  246.         window.removeEventListener('mousedown', onMouseDown, false);
  247.         window.removeEventListener('mouseup', onMouseUp, false);
  248.         window.removeEventListener('mousewheel', onMouseScroll, false);
  249.         window.removeEventListener('keydown', onKeyDown, false);
  250.         window.removeEventListener('keyup', onKeyUp, false);
  251.     }
  252. }
  253.  
  254. function onEditBtn(evt) {
  255.     if(!editBtnPressed) {
  256.         editBtnPressed = true;
  257.         cancelFrame(frameID[0]);
  258.         makeBtn.disabled = false;
  259.         sizeSelect.disabled = false;
  260.         canvasSelect.disabled = false;
  261.         inTextW.disabled = false;
  262.         inTextH.disabled = false;
  263.         inTextD.disabled = false;
  264.         changeWindowListeners(false);
  265.         if(!winState) {
  266.             mc.ct.clearRect(0, 0, mc.w, mc.h);
  267.             renderPrompt('click here to resume');
  268.             mc.cv.addEventListener('click', onCanvasClick, false);
  269.         }
  270.     }
  271. }
  272.  
  273. function onMakeBtn(evt) {
  274.     var w = inTextW.value, h = inTextH.value, d = inTextD.value;
  275.     inW = int(w);
  276.     if(!(inW >= 1)) {
  277.         inW = 5;
  278.     } else if(inW%2 == 0) {
  279.         inW = inW+1;
  280.     }
  281.     inH = int(h);
  282.     if(!(inH >= 1)) {
  283.         inH = 5;
  284.     } else if(inH%2 == 0) {
  285.         inH = inH+1;
  286.     }
  287.     inD = int(d);
  288.     if(!(inD >= 1)) {
  289.         inD = 5;
  290.     } else if(inD%2 == 0) {
  291.         inD = inD+1;
  292.     }
  293.     inTextW.value = inW.toString();
  294.     inTextH.value = inH.toString();
  295.     inTextD.value = inD.toString();
  296.     makeBtn.disabled = true;
  297.     sizeSelect.disabled = true;
  298.     canvasSelect.disabled = true;
  299.     inTextW.disabled = true;
  300.     inTextH.disabled = true;
  301.     inTextD.disabled = true;
  302.     editBtnPressed = false;
  303.     changeWindowListeners(true);
  304.     mc.cv.removeEventListener('click', onCanvasClick, false);
  305.     cancelFrame(frameID[1]);
  306.     init();
  307. }
  308.  
  309. function onInstructBtn(evt) {
  310.     var w = 800, h = 460;
  311.     var left = Math.floor(window.screen.width/2-w/2);
  312.     var top = 32;
  313.     open('help.html', 'instruction-popup', 'width='+w+', height='+h+', menubar=no, status=no, scrollbars=yes, resizable=yes, toolbar=no, location=no, left='+left+', top='+top);
  314. }
  315.  
  316. function onCanvasClick(evt) {
  317.     makeBtn.disabled = true;
  318.     sizeSelect.disabled = true;
  319.     canvasSelect.disabled = true;
  320.     inTextW.disabled = true;
  321.     inTextH.disabled = true;
  322.     inTextD.disabled = true;
  323.     editBtnPressed = false;
  324.     changeWindowListeners(true);
  325.     mc.cv.removeEventListener('click', onCanvasClick, false);
  326.     if(mcChange)
  327.         mc.updateSize(mcW, mcH, AspectMult);
  328.     if(!winState)
  329.         frameID[0] = requestFrame(output);
  330. }
  331.  
  332. function onSelectChange(evt) {
  333.     var t = evt.target;
  334.     switch(t.value) {
  335.     case 'a':
  336.         inTextW.value = inTextH.value = inTextD.value = '5';
  337.         break;
  338.     case 'b':
  339.         inTextW.value = inTextH.value = inTextD.value = '7';
  340.         break;
  341.     case 'c':
  342.         inTextW.value = inTextH.value = inTextD.value = '9';
  343.         break;
  344.     case 'd':
  345.         inTextW.value = inTextH.value = inTextD.value = '11';
  346.         break;
  347.     case 'e':
  348.         inTextW.value = inTextH.value = inTextD.value = '13';
  349.         break;
  350.     case 'f':
  351.         inTextW.value = '25';
  352.         inTextH.value = '25';
  353.         inTextD.value = '1';
  354.         break;
  355.     }
  356. }
  357.  
  358. function onCanvasChange(evt) {
  359.     mcChange = true;
  360.     var t = evt.target;
  361.     switch(t.value) {
  362.     case 'a':
  363.         mcW = 300;
  364.         mcH = 200;
  365.         break;
  366.     case 'b':
  367.         mcW = 600;
  368.         mcH = 400;
  369.         break;
  370.     case 'c':
  371.         mcW = 800;
  372.         mcH = 600;
  373.         break;
  374.     case 'd':
  375.         mcW = 1000;
  376.         mcH = 800;
  377.         break;
  378.     }
  379. }
  380.  
  381. function onTextChange(evt) {
  382.     sizeSelect.value = 'custom';
  383. }</script>
  384.     <script type="text/javascript">/*
  385.  * Stage One Maze
  386.  * Copyright (c) 2012 Sean McKean (smckean AT systemsymmetry DOT com)
  387.  *
  388.  * Permission is hereby granted, free of charge, to any person obtaining a
  389.  * copy of this software and associated documentation files (the "Software"),
  390.  * to deal in the Software without restriction, including without limitation
  391.  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  392.  * and/or sell copies of the Software, and to permit persons to whom the
  393.  * Software is furnished to do so, subject to the following conditions:
  394.  *
  395.  * The above copyright notice and this permission notice shall be included
  396.  * in all copies or substantial portions of the Software.
  397.  *
  398.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  399.  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  400.  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  401.  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
  402.  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  403.  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  404.  * OTHER DEALINGS IN THE SOFTWARE.
  405.  */
  406.  
  407. function Map(w, h, d) {
  408.     this.w = w, this.h = h, this.d = d;
  409.     this.maxDim = Math.max(w, h, d);
  410.     this.m = new Array(w*h*d);
  411.     for(var i = 0; i < this.m.length; i++)
  412.         this.m[i] = 1;
  413.     this.v = new Array(this.m.length);
  414.     this.rw = int(w/2+1), this.rh = int(h/2+1), this.rd = int(d/2+1);
  415.     this.oSpace = new Array(this.rw*this.rh*this.rd);
  416.     this.path = new Array(this.oSpace.length);
  417.     for(var i = 0; i < this.path.length; i++)
  418.         this.path[i] = {
  419.             x: { type: -1, view: -1, time: 0, r: 0, g: 0, b: 0, a: 0.0 },
  420.             y: { type: -1, view: -1, time: 0, r: 0, g: 0, b: 0, a: 0.0 },
  421.             z: { type: -1, view: -1, time: 0, r: 0, g: 0, b: 0, a: 0.0 } };
  422.     this.sw = w+1;  this.sh = h+1;  this.sd = d+1;
  423.     this.space = new Array(this.sw*this.sh*this.sd);
  424.     this.goal = { x: w-1, y: h-1, z: d-1 };
  425. }
  426.  
  427. Map.prototype.getMIndex = function(x, y, z) {
  428.     return z*this.w*this.h+y*this.w+x;
  429. }
  430.  
  431. Map.prototype.getRIndex = function(x, y, z) {
  432.     return z*this.rw*this.rh+y*this.rw+x;
  433. }
  434.  
  435. Map.prototype.getSIndex = function(x, y, z) {
  436.     return z*this.sw*this.sh+y*this.sw+x;
  437. }
  438.  
  439. Map.prototype.getCell = function(x, y, z) {
  440.     if(x >= 0 && x < this.w && y >= 0 && y < this.h && z >= 0 && z < this.d)
  441.         return this.m[ this.getMIndex(x, y, z) ];
  442.     return null;
  443. }
  444.  
  445. Map.prototype.setCell = function(x, y, z, v) {
  446.     this.m[ this.getMIndex(x, y, z) ] = v;
  447. }
  448.  
  449. Map.prototype.getCellPoint = function(pos, t0, d0, t1, d1, t2, d2) {
  450.     var p = new Object();
  451.     p[t0] = pos[t0]+d0;
  452.     p[t1] = pos[t1]+d1;
  453.     p[t2] = pos[t2]+d2;
  454.     return this.getCell(p.x, p.y, p.z);
  455. }
  456.  
  457. Map.prototype.getVCell = function(x, y, z) {
  458.     return this.v[ this.getMIndex(x, y, z) ];
  459. }
  460.  
  461. Map.prototype.setVCell = function(x, y, z, v) {
  462.     this.v[ this.getMIndex(x, y, z) ] = v;
  463. }
  464.  
  465. Map.prototype.getPathCell = function(x, y, z) {
  466.     return this.path[ this.getRIndex(x, y, z) ];
  467. }
  468.  
  469. Map.prototype.setPathCell = function(x, y, z, dim, name, value) {
  470.     this.path[ this.getRIndex(x, y, z) ][dim][name] = value;
  471. }
  472.  
  473. var visColors = [ { r: 0, g: 0, b: 159 }, { r: 159, g: 0, b: 0 } ];
  474.  
  475. function alphaValue(c, t) {
  476.     return clip(c.a+(1.0-c.a)*c.time, 0.0, 1.0);
  477. }
  478.  
  479. function getColor(c) {
  480.     if(c.type == 0 || c.view == 1) {
  481.         var t = 0;
  482.     } else {
  483.         var t = 1;
  484.     }
  485.     return RGBA(visColors[t].r, visColors[t].g, visColors[t].b, alphaValue(c,  t));
  486. }
  487.  
  488. function setColor(c) {
  489.     if(c.type == 0 || c.view == 1) {
  490.         var t = 0;
  491.     } else {
  492.         var t = 1;
  493.     }
  494.     c.r = visColors[t].r;
  495.     c.g = visColors[t].g;
  496.     c.b = visColors[t].b;
  497.     c.a = alphaValue(c, t);
  498. }
  499.  
  500. Map.prototype.setVisibleRoomFromCell = function(x, y, z, dim, view) {
  501.     var c = this.getPathCell(int(x/2), int(y/2), int(z/2))[dim];
  502.     if(c.view != 0) {
  503.         if(c.view > -1)
  504.             setColor(c);
  505.         c.time = eps;
  506.         c.view = view;
  507.     }
  508. }
  509.  
  510. Map.prototype.setVGroup = function(x, y, z, flag, v) {
  511.     switch(flag) {
  512.     case 0:  // Along x-axis
  513.         for(var i = y-1; i < y+2; i++)
  514.         for(var j = z-1; j < z+2; j++)
  515.             if(i >= 0 && i < this.h && j >= 0 && j < this.d)
  516.                 this.setVCell(x, i, j, v);
  517.         break;
  518.     case 1:  // Along y-axis
  519.         for(var i = x-1; i < x+2; i++)
  520.         for(var j = z-1; j < z+2; j++)
  521.             if(i >= 0 && i < this.w && j >= 0 && j < this.d)
  522.                 this.setVCell(i, y, j, v);
  523.         break;
  524.     case 2:  // Along z-axis
  525.         for(var i = x-1; i < x+2; i++)
  526.         for(var j = y-1; j < y+2; j++)
  527.             if(i >= 0 && i < this.w && j >= 0 && j < this.h)
  528.                 this.setVCell(i, j, z, v);
  529.         break;
  530.     }
  531. }
  532.  
  533. Map.prototype.setVisibleAxes = function(px, py, pz, dir) {
  534.     if(dir != 0) {
  535.         for(var x = px; x >= 0; x--) {
  536.             if(this.getCell(x, py, pz) == 0) {
  537.                 this.setVGroup(x, py, pz, 0, true);
  538.             } else {
  539.                 this.setVGroup(x, py, pz, 0, true);
  540.                 break;
  541.             }
  542.         }
  543.     }
  544.     if(dir != 1) {
  545.         for(var x = px; x < this.w; x++) {
  546.             if(this.getCell(x, py, pz) == 0) {
  547.                 this.setVGroup(x, py, pz, 0, true);
  548.             } else {
  549.                 this.setVGroup(x, py, pz, 0, true);
  550.                 break;
  551.             }
  552.         }
  553.     }
  554.     if(dir != 2) {
  555.         for(var y = py; y >= 0; y--) {
  556.             if(this.getCell(px, y, pz) == 0) {
  557.                 this.setVGroup(px, y, pz, 1, true);
  558.             } else {
  559.                 this.setVGroup(px, y, pz, 1, true);
  560.                 break;
  561.             }
  562.         }
  563.     }
  564.     if(dir != 3) {
  565.         for(var y = py; y < this.h; y++) {
  566.             if(this.getCell(px, y, pz) == 0) {
  567.                 this.setVGroup(px, y, pz, 1, true);
  568.             } else {
  569.                 this.setVGroup(px, y, pz, 1, true);
  570.                 break;
  571.             }
  572.         }
  573.     }
  574.     if(dir != 4) {
  575.         for(var z = pz; z >= 0; z--) {
  576.             if(this.getCell(px, py, z) == 0) {
  577.                 this.setVGroup(px, py, z, 2, true);
  578.             } else {
  579.                 this.setVGroup(px, py, z, 2, true);
  580.                 break;
  581.             }
  582.         }
  583.     }
  584.     if(dir != 5) {
  585.         for(var z = pz; z < this.d; z++) {
  586.             if(this.getCell(px, py, z) == 0) {
  587.                 this.setVGroup(px, py, z, 2, true);
  588.             } else {
  589.                 this.setVGroup(px, py, z, 2, true);
  590.                 break;
  591.             }
  592.         }
  593.     }
  594. }
  595.  
  596. Map.prototype.nonDeadEndRooms = function(x, y, z, d) {
  597.     var xx = x*2, yy = y*2, zz = z*2;
  598.     for(var i = 0; i < 2; i++) {
  599.         var c = 0;
  600.         if(xx > 0 && this.getCell(xx-1, yy, zz) == 0)
  601.             c++;
  602.         if(xx < this.w-1 && this.getCell(xx+1, yy, zz) == 0)
  603.             c++;
  604.         if(yy > 0 && this.getCell(xx, yy-1, zz) == 0)
  605.             c++;
  606.         if(yy < this.h-1 && this.getCell(xx, yy+1, zz) == 0)
  607.             c++;
  608.         if(zz > 0 && this.getCell(xx, yy, zz-1) == 0)
  609.             c++;
  610.         if(zz < this.d-1 && this.getCell(xx, yy, zz+1) == 0)
  611.             c++;
  612.         if(c < 2)
  613.             return false;
  614.         switch(d) {
  615.         case 'x':
  616.             xx += 2;
  617.             break;
  618.         case 'y':
  619.             yy += 2;
  620.             break;
  621.         case 'z':
  622.             zz += 2;
  623.             break;
  624.         }
  625.     }
  626.     return true;
  627. }
  628.  
  629. Map.prototype.setAllPaths = function() {
  630.     for(var z = 0; z < this.rd; z++)
  631.     for(var y = 0; y < this.rh; y++)
  632.     for(var x = 0; x < this.rw; x++) {
  633.         if(x < this.rw-1 && this.getCell(x*2+1, y*2, z*2) == 0) {
  634.             if(this.nonDeadEndRooms(x, y, z, 'x')) {
  635.                 this.setPathCell(x, y, z, 'x', 'type', 0);
  636.             } else {
  637.                 this.setPathCell(x, y, z, 'x', 'type', 1);
  638.             }
  639.         }
  640.         if(y < this.rh-1 && this.getCell(x*2, y*2+1, z*2) == 0) {
  641.             if(this.nonDeadEndRooms(x, y, z, 'y')) {
  642.                 this.setPathCell(x, y, z, 'y', 'type', 0);
  643.             } else {
  644.                 this.setPathCell(x, y, z, 'y', 'type', 1);
  645.             }
  646.         }
  647.         if(z < this.rd-1 && this.getCell(x*2, y*2, z*2+1) == 0) {
  648.             if(this.nonDeadEndRooms(x, y, z, 'z')) {
  649.                 this.setPathCell(x, y, z, 'z', 'type', 0);
  650.             } else {
  651.                 this.setPathCell(x, y, z, 'z', 'type', 1);
  652.             }
  653.         }
  654.     }
  655. }
  656.  
  657. Map.prototype.setSurroundingRoomsFromCell = function(x, y, z, d, v) {
  658.     if(d != 'x') {
  659.         if(x > 0 && this.getCell(x-1, y, z) == 0)
  660.             this.setVisibleRoomFromCell(x-1, y, z, 'x', v);
  661.         if(x < this.w-1 && this.getCell(x+1, y, z) == 0)
  662.             this.setVisibleRoomFromCell(x, y, z, 'x', v);
  663.     }
  664.     if(d != 'y') {
  665.         if(y > 0 && this.getCell(x, y-1, z) == 0)
  666.             this.setVisibleRoomFromCell(x, y-1, z, 'y', v);
  667.         if(y < this.h-1 && this.getCell(x, y+1, z) == 0)
  668.             this.setVisibleRoomFromCell(x, y, z, 'y', v);
  669.     }
  670.     if(d != 'z') {
  671.         if(z > 0 && this.getCell(x, y, z-1) == 0)
  672.             this.setVisibleRoomFromCell(x, y, z-1, 'z', v);
  673.         if(z < this.d-1 && this.getCell(x, y, z+1) == 0)
  674.             this.setVisibleRoomFromCell(x, y, z, 'z', v);
  675.     }
  676. }
  677.  
  678. Map.prototype.setSeenPathCells = function(plr) {
  679.     var x = int(plr.x), y = int(plr.y), z = int(plr.z);
  680.     if(x%2 == 1 || y%2 == 1 || z%2 == 1)
  681.         return;
  682.     for(var d = -1; d < 2; d += 2) {
  683.         for(var xx = x; xx >= 0 && xx < this.w; xx += d) {
  684.             if(this.getCell(xx, y, z) == 1)
  685.                 break;
  686.             if(xx%2 == 0)
  687.                 this.setSurroundingRoomsFromCell(xx, y, z, 'x', 1);
  688.             if(xx%2 == 1)
  689.                 this.setVisibleRoomFromCell(xx, y, z, 'x', 0);
  690.         }
  691.         for(var yy = y; yy >= 0 && yy < this.h; yy += d) {
  692.             if(this.getCell(x, yy, z) == 1)
  693.                 break;
  694.             if(yy%2 == 0)
  695.                 this.setSurroundingRoomsFromCell(x, yy, z, 'y', 1);
  696.             if(yy%2 == 1)
  697.                 this.setVisibleRoomFromCell(x, yy, z, 'y', 0);
  698.         }
  699.         for(var zz = z; zz >= 0 && zz < this.d; zz += d) {
  700.             if(this.getCell(x, y, zz) == 1)
  701.                 break;
  702.             if(zz%2 == 0)
  703.                 this.setSurroundingRoomsFromCell(x, y, zz, 'z', 1);
  704.             if(zz%2 == 1)
  705.                 this.setVisibleRoomFromCell(x, y, zz, 'z', 0);
  706.         }
  707.     }
  708. }
  709.  
  710. Map.prototype.setVisibleCells = function(plr) {
  711.     for(var z = 0; z < this.d; z++)
  712.     for(var y = 0; y < this.h; y++)
  713.     for(var x = 0; x < this.w; x++)
  714.         this.setVCell(x, y, z, false);
  715.     var x = int(plr.x), y = int(plr.y), z = int(plr.z);
  716.     if(x < this.w-1)
  717.         this.setVisibleAxes(x+1, y, z, 0);
  718.     if(x > 0)
  719.         this.setVisibleAxes(x-1, y, z, 1);
  720.     if(y < this.h-1)
  721.         this.setVisibleAxes(x, y+1, z, 2);
  722.     if(y > 0)
  723.         this.setVisibleAxes(x, y-1, z, 3);
  724.     if(z < this.d-1)
  725.         this.setVisibleAxes(x, y, z+1, 4);
  726.     if(z > 0)
  727.         this.setVisibleAxes(x, y, z-1, 5);
  728. }
  729.  
  730. Map.prototype.sideExists = function(pos, side) {
  731.     switch(side) {
  732.     case 0:
  733.         if(pos.z == 0 || this.getCell(pos.x, pos.y, pos.z-1) == 1)
  734.             return false;
  735.         break;
  736.     case 1:
  737.         if(pos.z == this.d-1 || this.getCell(pos.x, pos.y, pos.z+1) == 1)
  738.             return false;
  739.         break;
  740.     case 2:
  741.         if(pos.y == 0 || this.getCell(pos.x, pos.y-1, pos.z) == 1)
  742.             return false;
  743.         break;
  744.     case 3:
  745.         if(pos.y == this.h-1 || this.getCell(pos.x, pos.y+1, pos.z) == 1)
  746.             return false;
  747.         break;
  748.     case 4:
  749.         if(pos.x == 0 || this.getCell(pos.x-1, pos.y, pos.z) == 1)
  750.             return false;
  751.         break;
  752.     case 5:
  753.         if(pos.x == this.w-1 || this.getCell(pos.x+1, pos.y, pos.z) == 1)
  754.             return false;
  755.         break;
  756.     }
  757.     return true;
  758. }
  759.  
  760. var dimName = { x: 'w', y: 'h', z: 'd' };
  761.  
  762. Map.prototype.edgeIsDrawn = function(pos, side, edge) {
  763.     var p0 = points[ prePolies[side][edge] ], p1 = points[ prePolies[side][(edge+1)%4] ];
  764.     if(p1.x-p0.x != 0) {
  765.         var t0 = 'y', t1 = 'z', t2 = 'x';
  766.     } else if(p1.y-p0.y != 0) {
  767.         var t0 = 'x', t1 = 'z', t2 = 'y';
  768.     } else if(p1.z-p0.z != 0) {
  769.         var t0 = 'x', t1 = 'y', t2 = 'z';
  770.     } else {
  771.         alert('Bad data passed to Map.edgeIsDrawn()');
  772.         return false;
  773.     }
  774.     if(pos[t0] == p0[t0]*(this[ dimName[t0] ]-1) || pos[t1] == p0[t1]*(this[ dimName[t1] ]-1))
  775.         return true;
  776.     if(this.getCellPoint(pos, t0, p0[t0]*2-1, t1, p0[t1]*2-1, t2, 0) == 1)
  777.         return true;
  778.     if(this.getCellPoint(pos, t0, p0[t0]*2-1, t1, 0, t2, 0) == 1)
  779.         return false;
  780.     if(this.getCellPoint(pos, t0, 0, t1, p0[t1]*2-1, t2, 0) == 1)
  781.         return false;
  782.     return true;
  783. }
  784.  
  785. var adjAry = [ [ 1, 0, 0 ], [ 0, 1, 0 ], [ 0, 0, 1 ], [ 1, 1, 0 ], [ 1, 0, 1 ], [ 0, 1, 1 ], [ 1, 1, 1 ] ];
  786.  
  787. Map.prototype.handleCollisions = function(plr, near, dim) {
  788.     var x = 0, y = 0, z = 0;
  789.     if(plr.x%1.0 < near && int(plr.x) > 0) {
  790.         x = -1;
  791.     } else if(plr.x%1.0 > 1.0-near && int(plr.x) < this.w-1) {
  792.         x = 1;
  793.     }
  794.     if(plr.y%1.0 < near && int(plr.y) > 0) {
  795.         y = -1;
  796.     } else if(plr.y%1.0 > 1.0-near && int(plr.y) < this.h-1) {
  797.         y = 1;
  798.     }
  799.     if(plr.z%1.0 < near && int(plr.z) > 0) {
  800.         z = -1;
  801.     } else if(plr.z%1.0 > 1.0-near && int(plr.z) < this.d-1) {
  802.         z = 1;
  803.     }
  804.     var col = false;
  805.     for(var i = 0; i < adjAry.length; i++) {
  806.         var xx = (adjAry[i][0] == 1) ? x : 0;
  807.         var yy = (adjAry[i][1] == 1) ? y : 0;
  808.         var zz = (adjAry[i][2] == 1) ? z : 0;
  809.         if(this.getCell(int(plr.x)+xx, int(plr.y)+yy, int(plr.z)+zz) == 1) {
  810.             col = true;
  811.             break;
  812.         }
  813.     }
  814.     if(col) {
  815.         switch(dim) {
  816.         case 'x':
  817.             if(x == 1) {
  818.                 plr.x = int(plr.x)+1-near-eps;
  819.                 return;
  820.             } else if(x == -1) {
  821.                 plr.x = int(plr.x)+near+eps;
  822.                 return;
  823.             }
  824.             break;
  825.         case 'y':
  826.             if(y == 1) {
  827.                 plr.y = int(plr.y)+1-near-eps;
  828.                 return;
  829.             } else if(y == -1) {
  830.                 plr.y = int(plr.y)+near+eps;
  831.                 return;
  832.             }
  833.             break;
  834.         case 'z':
  835.             if(z == 1) {
  836.                 plr.z = int(plr.z)+1-near-eps;
  837.                 return;
  838.             } else if(z == -1) {
  839.                 plr.z = int(plr.z)+near+eps;
  840.                 return;
  841.             }
  842.             break;
  843.         }
  844.     }
  845. }
  846.  
  847. Map.prototype.getSpace = function(x, y, z) {
  848.     return this.space[ this.getSIndex(x, y, z) ];
  849. }
  850.  
  851. Map.prototype.setSpace = function(x, y, z, v) {
  852.     this.space[ this.getSIndex(x, y, z) ] = v;
  853. }
  854.  
  855. Map.prototype.fillSpace = function(plr, tm) {
  856.     for(var z = 0; z < this.sd; z += this.sd-1)
  857.     for(var y = 0; y < this.sh; y += this.sh-1)
  858.     for(var x = 0; x < this.sw; x += this.sw-1) {
  859.         var mat = multiplyMatrices([ [ x-plr.x, y-plr.y, z-plr.z, 1 ] ], tm);
  860.         this.setSpace(x, y, z, new SpacePoint(mat[0][0], mat[0][1], mat[0][2]));
  861.     }
  862.     if(this.sw > 2) {
  863.         for(var z = 0; z < this.sd; z += this.sd-1)
  864.         for(var y = 0; y < this.sh; y += this.sh-1)
  865.         for(var x = 1; x < this.sw; x++) {
  866.             var f = x/(this.sw-1);
  867.             var p = interpPoint(this.getSpace(0, y, z), this.getSpace(this.sw-1, y, z), f);
  868.             this.setSpace(x, y, z, p);
  869.         }
  870.     }
  871.     if(this.sh > 2) {
  872.         for(var z = 0; z < this.sd; z += this.sd-1)
  873.         for(var y = 1; y < this.sh; y++)
  874.         for(var x = 0; x < this.sw; x++) {
  875.             var f = y/(this.sh-1);
  876.             var p = interpPoint(this.getSpace(x, 0, z), this.getSpace(x, this.sh-1, z), f);
  877.             this.setSpace(x, y, z, p);
  878.         }
  879.     }
  880.     if(this.sd > 2) {
  881.         for(var z = 1; z < this.sd; z++)
  882.         for(var y = 0; y < this.sh; y++)
  883.         for(var x = 0; x < this.sw; x++) {
  884.             var f = z/(this.sd-1);
  885.             var p = interpPoint(this.getSpace(x, y, 0), this.getSpace(x, y, this.sd-1), f);
  886.             this.setSpace(x, y, z, p);
  887.         }
  888.     }
  889. }
  890.  
  891. Map.prototype.getOSpace = function(x, y, z) {
  892.     return this.oSpace[ this.getRIndex(x, y, z) ];
  893. }
  894.  
  895. Map.prototype.setOSpace = function(x, y, z, v) {
  896.     this.oSpace[ this.getRIndex(x, y, z) ] = v;
  897. }
  898.  
  899. Map.prototype.fillOverviewSpace = function(plr, tm) {
  900.     var w = (this.rw == 1) ? 2 : this.rw;
  901.     var h = (this.rh == 1) ? 2 : this.rh;
  902.     var d = (this.rd == 1) ? 2 : this.rd;
  903.     for(var z = 0; z < this.rd; z += d-1)
  904.     for(var y = 0; y < this.rh; y += h-1)
  905.     for(var x = 0; x < this.rw; x += w-1) {
  906.         var mat0 = [ [ x+0.25-plr.x/2, y+0.25-plr.y/2, z+0.25-plr.z/2, 1 ] ];
  907.         var mat1 = multiplyMatrices(mat0, tm);
  908.         this.setOSpace(x, y, z, new SpacePoint(mat1[0][0], mat1[0][1], mat1[0][2]));
  909.     }
  910.     if(this.rw > 1) {
  911.         for(var z = 0; z < this.rd; z += d-1)
  912.         for(var y = 0; y < this.rh; y += h-1)
  913.         for(var x = 1; x < w; x++) {
  914.             var f = x/(w-1);
  915.             var p = interpPoint(this.getOSpace(0, y, z), this.getOSpace(w-1, y, z), f);
  916.             this.setOSpace(x, y, z, p);
  917.         }
  918.     }
  919.     if(this.rh > 1) {
  920.         for(var z = 0; z < this.rd; z += d-1)
  921.         for(var y = 1; y < h; y++)
  922.         for(var x = 0; x < this.rw; x++) {
  923.             var f = y/(h-1);
  924.             var p = interpPoint(this.getOSpace(x, 0, z), this.getOSpace(x, h-1, z), f);
  925.             this.setOSpace(x, y, z, p);
  926.         }
  927.     }
  928.     if(this.rd > 1) {
  929.         for(var z = 1; z < d; z++)
  930.         for(var y = 0; y < this.rh; y++)
  931.         for(var x = 0; x < this.rw; x++) {
  932.             var f = z/(d-1);
  933.             var p = interpPoint(this.getOSpace(x, y, 0), this.getOSpace(x, y, d-1), f);
  934.             this.setOSpace(x, y, z, p);
  935.         }
  936.     }
  937. }
  938.  
  939. Map.prototype.makeMaze = function(xs, ys, zs) {
  940.     this.setCell(xs, ys, zs, 0);
  941.     var x = xs, y = ys, z = zs;
  942.     var c = 1, full = (int(this.w/2+1)*int(this.h/2+1)*int(this.d/2+1));
  943.     var rc = 1;
  944.     var cellStack = [ { x: x, y: y, z: z } ];
  945.     var stackPtr = 0;
  946.     while(c < full) {
  947.         var open = new Array();
  948.         if(x < this.w-1 && this.getCell(x+2, y, z) == 1)
  949.             open.push(0);
  950.         if(x > 0 && this.getCell(x-2, y, z) == 1)
  951.             open.push(1);
  952.         if(y < this.h-1 && this.getCell(x, y+2, z) == 1)
  953.             open.push(2);
  954.         if(y > 0 && this.getCell(x, y-2, z) == 1)
  955.             open.push(3);
  956.         if(z < this.d-1 && this.getCell(x, y, z+2) == 1)
  957.             open.push(4);
  958.         if(z > 0 && this.getCell(x, y, z-2) == 1)
  959.             open.push(5);
  960.         if(open.length == 0) {
  961.             cellStack.splice(stackPtr, 1);
  962.             stackPtr = int(Math.random()*cellStack.length);
  963.             x = cellStack[stackPtr].x;
  964.             y = cellStack[stackPtr].y;
  965.             z = cellStack[stackPtr].z;
  966.             continue;
  967.         }
  968.         var dir = open[ int(Math.random()*open.length) ];
  969.         switch(dir) {
  970.         case 0:
  971.             this.setCell(x+1, y, z, 0);
  972.             this.setCell(x+2, y, z, 0);
  973.             x += 2;
  974.             break;
  975.         case 1:
  976.             this.setCell(x-1, y, z, 0);
  977.             this.setCell(x-2, y, z, 0);
  978.             x -= 2;
  979.             break;
  980.         case 2:
  981.             this.setCell(x, y+1, z, 0);
  982.             this.setCell(x, y+2, z, 0);
  983.             y += 2;
  984.             break;
  985.         case 3:
  986.             this.setCell(x, y-1, z, 0);
  987.             this.setCell(x, y-2, z, 0);
  988.             y -= 2;
  989.             break;
  990.         case 4:
  991.             this.setCell(x, y, z+1, 0);
  992.             this.setCell(x, y, z+2, 0);
  993.             z += 2;
  994.             break;
  995.         case 5:
  996.             this.setCell(x, y, z-1, 0);
  997.             this.setCell(x, y, z-2, 0);
  998.             z -= 2;
  999.             break;
  1000.         }
  1001.         cellStack.push({ x: x, y: y, z: z });
  1002.         c++;
  1003.         rc++;
  1004.         if(rc == MaxRun) {
  1005.             stackPtr = int(Math.random()*(cellStack.length-1));
  1006.             x = cellStack[stackPtr].x;
  1007.             y = cellStack[stackPtr].y;
  1008.             z = cellStack[stackPtr].z;
  1009.             rc = 0;
  1010.         }
  1011.     }
  1012. }</script>
  1013.     <script type="text/javascript">/*
  1014.  * Stage One Maze
  1015.  * Copyright (c) 2012 Sean McKean (smckean AT systemsymmetry DOT com)
  1016.  *
  1017.  * Permission is hereby granted, free of charge, to any person obtaining a
  1018.  * copy of this software and associated documentation files (the "Software"),
  1019.  * to deal in the Software without restriction, including without limitation
  1020.  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  1021.  * and/or sell copies of the Software, and to permit persons to whom the
  1022.  * Software is furnished to do so, subject to the following conditions:
  1023.  *
  1024.  * The above copyright notice and this permission notice shall be included
  1025.  * in all copies or substantial portions of the Software.
  1026.  *
  1027.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  1028.  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  1029.  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  1030.  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
  1031.  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
  1032.  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  1033.  * OTHER DEALINGS IN THE SOFTWARE.
  1034.  */
  1035.  
  1036. Debug = false;
  1037. var mc, bc, wc;
  1038. var mcW, mcH, mcChange;
  1039. var AspectMult = 0.72;
  1040. var editBtn, editBtnPressed;
  1041. var makeBtn, winCheck, sizeSelect, instructBtn, canvasSelect;
  1042. var inTextW, inTextH, inTextD;
  1043. var inW, inH, inD;
  1044. var points = [ 
  1045.     { x: 0, y: 0, z: 0 }, { x: 1, y: 0, z: 0 }, { x: 1, y: 1, z: 0 }, { x: 0, y: 1, z: 0 },
  1046.     { x: 0, y: 0, z: 1 }, { x: 1, y: 0, z: 1 }, { x: 1, y: 1, z: 1 }, { x: 0, y: 1, z: 1 } ];
  1047. var prePolies = [ [ 0, 1, 2, 3 ], [ 5, 4, 7, 6 ], [ 0, 4, 5, 1 ], [ 7, 3, 2, 6 ], [ 0, 3, 7, 4 ], [ 2, 1, 5, 6 ] ];
  1048. var polyVerts, polyDrawn, polyToCube;
  1049. var plr, plrSpeed;
  1050. var restart;
  1051. var tm;
  1052. var map;
  1053. var mapZoom;
  1054. var MapZoomMult = 1.2;
  1055. var MaxRun = 8;
  1056. var PathTimeInc = 0.03;
  1057. var goalDis;
  1058. var goalRad;
  1059. var goalAlpha, goalAngle;
  1060. var GoalAngleDelta = 0.04;
  1061. var winState, winAlpha;
  1062. var keys = {
  1063.     w: 0, s: 0, a: 0, d: 0, q: 0, e: 0, r: 0, f: 0, z: 0, x: 0, c: 0, v: 0,
  1064.     tab: false, spc: false, minus: false, plus: false };
  1065. var msx = -1, msy = -1;
  1066. var mbstate = [ 0, 0, 0 ];
  1067. var mbpos = { x: -1, y: -1 };
  1068. var KeyDelta = 0.036;
  1069. var MouseDelta = 0.012;
  1070. var SpeedDelta = 0.002;
  1071. var MaxSpeed = KeyDelta*2;
  1072. var zNear = 0.02;
  1073. var wallNear = 0.24;
  1074. var criticalFlag = 0.0;
  1075. var showMap;
  1076.  
  1077. var Pi = Math.PI;
  1078. var Circ = 2.0*Pi;
  1079. var eps = 0.00001;
  1080.  
  1081. var requestFrame;
  1082. var cancelFrame;
  1083. var frameID = new Array(2);
  1084. var frames;
  1085.  
  1086. function int(n) {
  1087.     return Math.floor(n);
  1088. }
  1089.  
  1090. // Clips value v between min and max values
  1091. function clip(v, min, max) {
  1092.     if(v < min) {
  1093.         return min;
  1094.     } else if(v > max) {
  1095.         return max;
  1096.     }
  1097.     return v;
  1098. }
  1099.  
  1100. // Similar to clip, flooring to an integer
  1101. function clipInt(v, min, max) {
  1102.     if(v < min) {
  1103.         return int(min);
  1104.     } else if(v > max) {
  1105.         return int(max);
  1106.     }
  1107.     return int(v);
  1108. }
  1109.  
  1110. function RGB(r, g, b) {
  1111.     return 'rgb('+r+','+g+','+b+')';
  1112. }
  1113.  
  1114. function RGBA(r, g, b, a) {
  1115.     return 'rgba('+r+','+g+','+b+','+a+')';
  1116. }
  1117.  
  1118. // Pixel xy-coordinates
  1119. function ScreenPoint(x, y) {
  1120.     this.x = x;
  1121.     this.y = y;
  1122. }
  1123.  
  1124. // Contains 3d xyz-components
  1125. function SpacePoint(x, y, z) {
  1126.     this.x = x;
  1127.     this.y = y;
  1128.     this.z = z;
  1129. }
  1130.  
  1131. function Canvas(arg0, am) {
  1132.     if(typeof(arg0) == 'string') {
  1133.         this.cv = document.getElementById(arg0);
  1134.     } else {
  1135.         this.cv = document.createElement('canvas');
  1136.         this.cv.width = arg0[0];
  1137.         this.cv.height = arg0[1];
  1138.     }
  1139.     this.ct = this.cv.getContext('2d');
  1140.     if(!this.ct)
  1141.         alert('Unable to create 2D context for canvas');
  1142.     this.w = this.cv.width;
  1143.     this.h = this.cv.height;
  1144.     this.hw = int(this.w/2);
  1145.     this.hh = int(this.h/2);
  1146.     this.a = int(Math.min(this.w, this.h)*am);
  1147. }
  1148.  
  1149. Canvas.prototype.updateSize = function(w, h, am) {
  1150.     this.cv.width = this.w = w;
  1151.     this.cv.height = this.h = h;
  1152.     this.hw = int(this.w/2);
  1153.     this.hh = int(this.h/2);
  1154.     this.a = int(Math.min(this.w, this.h)*am);
  1155. }
  1156.  
  1157. function identityMatrix() {
  1158.     return [ [ 1, 0, 0, 0 ], [ 0, 1, 0, 0 ], [ 0, 0, 1, 0 ], [ 0, 0, 0, 1 ] ];
  1159. }
  1160.  
  1161. function multiplyMatrices(m0, m1) {
  1162.     var height = m0.length;
  1163.     var width = m1[0].length;
  1164.     var result = new Array(height);
  1165.     for(var y = 0; y < height; y++) {
  1166.         result[y] = new Array(width);
  1167.         for(var x = 0; x < width; x++) {
  1168.             var sum = 0;
  1169.             for(var z = 0; z < width; z++)
  1170.                 sum += m0[y][z]*m1[z][x];
  1171.             result[y][x] = sum;
  1172.         }
  1173.     }
  1174.     return result;
  1175. }
  1176.  
  1177. // Multiply rotation matrix by selected matrix to rotate points incrementally.
  1178. function rotateMatrix(m, x, y, z) {
  1179.     if(x) {
  1180.         var c = Math.cos(x);
  1181.         var s = Math.sin(x);
  1182.         var temp = [ [1, 0, 0, 0], [0, c, -s, 0], [0, s, c, 0], [0, 0, 0, 1] ];
  1183.         m = multiplyMatrices(m, temp);
  1184.     }
  1185.     if(y) {
  1186.         var c = Math.cos(y);
  1187.         var s = Math.sin(y);
  1188.         var temp = [ [c, 0, s, 0], [0, 1, 0, 0], [-s, 0, c, 0], [0, 0, 0, 1] ];
  1189.         m = multiplyMatrices(m, temp);
  1190.     }
  1191.     if(z) {
  1192.         var c = Math.cos(z);
  1193.         var s = Math.sin(z);
  1194.         var temp = [ [c, -s, 0, 0], [s, c, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1] ];
  1195.         m = multiplyMatrices(m, temp);
  1196.     }
  1197.     return m;
  1198. }
  1199.  
  1200. // Interpolates from p0 to p1 with the given ratio factor
  1201. function interpPoint(p0, p1, factor) {
  1202.     var x = (p1.x-p0.x)*factor+p0.x;
  1203.     var y = (p1.y-p0.y)*factor+p0.y;
  1204.     var z = (p1.z-p0.z)*factor+p0.z;
  1205.     return new SpacePoint(x, y, z);
  1206. }
  1207.  
  1208. // Converts a 3d SpacePoint to a ScreenPoint centered on the given Canvas.
  1209. function flattenPoint(p, c) {
  1210.     return new ScreenPoint(int(p.x*c.a/p.z+c.hw), int(p.y*c.a/p.z+c.hh));
  1211. }
  1212.  
  1213. function linePoints(p0, p1, canv) {
  1214.     if(p0.z < zNear) {
  1215.         if(p1.z < zNear)
  1216.             return null;
  1217.         var pt = interpPoint(p0, p1, (zNear-p0.z)/(p1.z-p0.z));
  1218.         var fp = flattenPoint(pt, canv);
  1219.         return [ fp, flattenPoint(p1, canv), false ];
  1220.     } else if(p1.z < zNear) {
  1221.         var pt = interpPoint(p0, p1, (zNear-p0.z)/(p1.z-p0.z));
  1222.         var fp = flattenPoint(pt, canv);
  1223.         return [ flattenPoint(p0, canv), fp, true ];
  1224.     }
  1225.     return [ flattenPoint(p0, canv), flattenPoint(p1, canv), false ];
  1226. }
  1227.  
  1228. function getFlatLines(s, p, d) {
  1229.     var flatLines = new Array();
  1230.     var len = s.length;
  1231.     var last = null;
  1232.     var nullCount = 0;
  1233.     // First space point is guaranteed to be ahead of view z-wise, but may be offscreen.
  1234.     for(var i = 0; i < len; i++) {
  1235.         var j = (i+1)%len;
  1236.         var ary = linePoints(s[i], s[j], mc);
  1237.         if(ary != null) {
  1238.             if(ary[2] == true) {
  1239.                 var line = { f0: ary[0], f1: ary[1], p0: p[i], p1: p[j], draw: d[i] };
  1240.                 flatLines.push(line);
  1241.                 last = ary[1];
  1242.             } else {
  1243.                 if(last != null) {
  1244.                     var fl = { f0: last, f1: ary[0], p0: p[i], p1: p[j], draw: false };
  1245.                     flatLines.push(fl);
  1246.                     last = null;
  1247.                 }
  1248.                 var line = { f0: ary[0], f1: ary[1], p0: p[i], p1: p[j], draw: d[i] };
  1249.                 flatLines.push(line);
  1250.             }
  1251.         } else {
  1252.             var fl = { f0: null, f1: null, draw: false };
  1253.             flatLines.push(fl);
  1254.             nullCount++;
  1255.         }
  1256.     }
  1257.     if(nullCount == 4)
  1258.         return null;
  1259.     return flatLines;
  1260. }
  1261.  
  1262. function handleMapKeys() {
  1263.     if(keys.tab) {
  1264.         showMap = !showMap;
  1265.         keys.tab = false;
  1266.     }
  1267.     if(keys.plus) {
  1268.         mapZoom = clip(mapZoom*MapZoomMult, 1.0, 16.0);
  1269.         keys.plus = false;
  1270.     }
  1271.     if(keys.minus) {
  1272.         mapZoom = clip(mapZoom/MapZoomMult, 1.0, 16.0);
  1273.         keys.minus = false;
  1274.     }
  1275. }
  1276.  
  1277. function handleRotation() {
  1278.     var x = keys.w-keys.s, y = keys.d-keys.a, z = keys.e-keys.q;
  1279.     tm = rotateMatrix(tm, x*KeyDelta, y*KeyDelta, z*KeyDelta);
  1280.     if(mouseButtonPrecedence(2, 1)) {
  1281.         var x = mbpos.y-msy, y = msx-mbpos.x;
  1282.         tm = rotateMatrix(tm, x*MouseDelta, y*MouseDelta, 0);
  1283.         mbpos = { x: msx, y: msy };
  1284.     } else if(mbstate[0] > 0 && mouseButtonPrecedence(1, 2)) {
  1285.         var z = msx-mbpos.x;
  1286.         tm = rotateMatrix(tm, 0, 0, z*MouseDelta);
  1287.         mbpos.x = msx;
  1288.     }
  1289. }
  1290.  
  1291. function solveLinearEquation(tm, x, y, z) {
  1292.     var m = identityMatrix();
  1293.     for(var yy = 0; yy < 3; yy++)
  1294.     for(var xx = 0; xx < 3; xx++) {
  1295.         m[yy][xx] = tm[yy][xx];
  1296.     }
  1297.     var xx = null, yy = null, zz = null;
  1298.     if(Math.abs(m[0][0]) > eps) {
  1299.         var f = m[0][1]/m[0][0];
  1300.         m[0][1] = 0.0;  m[1][1] -= m[1][0]*f;  m[2][1] -= m[2][0]*f;  y -= x*f;
  1301.         f = m[0][2]/m[0][0];
  1302.         m[0][2] = 0.0;  m[1][2] -= m[1][0]*f;  m[2][2] -= m[2][0]*f;  z -= x*f;
  1303.         if(Math.abs(m[1][1]) > eps) {
  1304.             f = m[1][2]/m[1][1];
  1305.             m[2][2] -= m[2][1]*f;  z -= y*f;
  1306.             zz = z/m[2][2];
  1307.             yy = (y-m[2][1]*zz)/m[1][1];
  1308.         } else {
  1309.             zz = y/m[2][1];
  1310.             yy = (z-m[2][2]*zz)/m[1][2];
  1311.         }
  1312.         xx = (x-m[1][0]*yy-m[2][0]*zz)/m[0][0];
  1313.     } else if(Math.abs(m[1][0]) > eps) {
  1314.         var f = m[1][1]/m[1][0];
  1315.         m[1][1] = 0.0;  m[2][1] -= m[2][0]*f;  y -= x*f;
  1316.         f = m[1][2]/m[1][0];
  1317.         m[1][2] = 0.0;  m[2][2] -= m[2][0]*f;  z -= x*f;
  1318.         if(Math.abs(m[0][1]) > eps) {
  1319.             f = m[0][2]/m[0][1];
  1320.             m[2][2] -= m[2][1]*f;  z -= y*f;
  1321.             zz = z/m[2][2];
  1322.             xx = (y-m[2][1]*zz)/m[0][1];
  1323.         } else {
  1324.             zz = y/m[2][1];
  1325.             xx = (z-m[2][2]*zz)/m[0][2];
  1326.         }
  1327.         yy = (x-m[2][0]*zz)/m[1][0];
  1328.     } else if(Math.abs(m[2][0]) > eps) {
  1329.         zz = x/m[2][0];
  1330.         if(Math.abs(m[0][1]) > eps) {
  1331.             var f = m[0][2]/m[0][1];
  1332.             m[1][2] -= m[1][1]*f;  z -= y*f;
  1333.             yy = z/m[1][2];
  1334.             xx = (y-yy*m[1][1]-zz*m[2][1])/m[0][1];
  1335.         } else {
  1336.             yy = y/m[1][1];
  1337.             xx = (z-yy*m[1][2]-zz*m[2][2])/m[0][2];
  1338.         }
  1339.     }
  1340.     var badResult = false;
  1341.     if(xx == null || yy == null || zz == null || xx != xx || yy != yy || zz != zz)
  1342.         badResult = true;
  1343.     if(Math.abs(xx) == Infinity || Math.abs(yy) == Infinity || Math.abs(zz) == Infinity)
  1344.         badResult = true;
  1345.     if(badResult) {
  1346.         console.log('obtained bad result in solve function: ', xx, yy, zz);
  1347.         criticalFlag = 1.0;
  1348.         return new SpacePoint(0.0, 0.0, 0.0);
  1349.     }
  1350.     return new SpacePoint(xx, yy, zz);
  1351. }
  1352.  
  1353. function distanceCompare(a, b) {
  1354.     if(a.c == null)
  1355.         return -1;
  1356.     if(b.c == null)
  1357.         return 1;
  1358.     // Greater distance gets drawn first.
  1359.     var d1 = b.c.x*b.c.x+b.c.y*b.c.y+b.c.z*b.c.z;
  1360.     var d0 = a.c.x*a.c.x+a.c.y*a.c.y+a.c.z*a.c.z;
  1361.     return d1-d0;
  1362. }
  1363.  
  1364. function handleMovement() {
  1365.     if(map.getCell(int(plr.x), int(plr.y), int(plr.z)) == 1) {
  1366.         console.log('Player inside a wall: ', plr.x, plr.y, plr.z);
  1367.         criticalFlag = 1.0;
  1368.         plr.x = restart.x;  plr.y = restart.y;  plr.z = restart.z;
  1369.     }
  1370.     var x = (keys.v-keys.z)*KeyDelta;
  1371.     var y = (keys.x-keys.c)*KeyDelta;
  1372.     var z = (keys.r-keys.f)*KeyDelta;
  1373.     if(mbstate[0] > 0 && mouseButtonPrecedence(1, 2)) {
  1374.         plrSpeed = clip(plrSpeed+(mbpos.y-msy)*SpeedDelta, -MaxSpeed, MaxSpeed);
  1375.         mbpos.y = msy;
  1376.     }
  1377.     z = clip(z+plrSpeed, -MaxSpeed, MaxSpeed);
  1378.     if(mbstate[0] == 0 && mouseButtonPrecedence(1, 2)) {
  1379.         x = clip(x+(msx-mbpos.x)*KeyDelta, -KeyDelta, KeyDelta);
  1380.         y = clip(y+(msy-mbpos.y)*KeyDelta, -KeyDelta, KeyDelta);
  1381.         mbpos = { x: msx, y: msy };
  1382.     }
  1383.     var offset = solveLinearEquation(tm, x, y, z);
  1384.     // Add offset vector to player coordinates one dimension at a time,
  1385.     // correcting for collisions.
  1386.     // First handle outer maze limits, then handle inner cubes.
  1387.     var t = plr.x;
  1388.     plr.x = clip(plr.x+offset.x, wallNear, map.w-wallNear);
  1389.     map.handleCollisions(plr, wallNear, 'x');
  1390.     if(plr.x != plr.x)  // NaN
  1391.         plr.x = t;
  1392.     var t = plr.y;
  1393.     plr.y = clip(plr.y+offset.y, wallNear, map.h-wallNear);
  1394.     map.handleCollisions(plr, wallNear, 'y');
  1395.     if(plr.y != plr.y)  // NaN
  1396.         plr.y = t;
  1397.     var t = plr.z;
  1398.     plr.z = clip(plr.z+offset.z, wallNear, map.d-wallNear);
  1399.     map.handleCollisions(plr, wallNear, 'z');
  1400.     if(plr.z != plr.z)  // NaN
  1401.         plr.z = t;
  1402. }
  1403.  
  1404. function setPixel(data, w, h, x, y, rc, gc, bc, ac) {
  1405.     if(x < 0 || x >= w || y < 0 || y >= h)
  1406.         return;
  1407.     var i = (y*w+x)*4;
  1408.     data[i] = rc;
  1409.     data[i+1] = gc;
  1410.     data[i+2] = bc;
  1411.     data[i+3] = ac;
  1412. }
  1413.  
  1414. function getGoalAlpha() {
  1415.     var a = 0.28*Math.cos(goalAngle)+0.72;
  1416.     goalAngle = (goalAngle+GoalAngleDelta)%Circ;
  1417.     return a;
  1418. }
  1419.  
  1420. function showFPS() {
  1421.     var div = document.getElementById('fpsCount');
  1422.     div.innerHTML = frames.toString();
  1423.     frames = 0;
  1424. }
  1425.  
  1426. function preInit() {
  1427.     editBtn = document.getElementById('edit');
  1428.     editBtn.addEventListener('click', onEditBtn, false);
  1429.     editBtnPressed = false;
  1430.     makeBtn = document.getElementById('makeMaze');
  1431.     makeBtn.addEventListener('click', onMakeBtn, false);
  1432.     winCheck = document.getElementById('winCheck');
  1433.     sizeSelect = document.getElementById('sizes');
  1434.     sizeSelect.addEventListener('change', onSelectChange, false);;
  1435.     instructBtn = document.getElementById('instructions');
  1436.     instructBtn.addEventListener('click', onInstructBtn, false);
  1437.     canvasSelect = document.getElementById('canvasSizes');
  1438.     canvasSelect.addEventListener('change', onCanvasChange, false);
  1439.     inTextW = document.getElementById('width');
  1440.     inTextH = document.getElementById('height');
  1441.     inTextD = document.getElementById('depth');
  1442.     inTextW.addEventListener('change', onTextChange, false);
  1443.     inTextH.addEventListener('change', onTextChange, false);
  1444.     inTextD.addEventListener('change', onTextChange, false);
  1445.  
  1446.     window.addEventListener('contextmenu', disableEvent, false);
  1447.     changeWindowListeners(true);
  1448.  
  1449.     inW = int(inTextW.value), inH = int(inTextH.value), inD = int(inTextD.value);
  1450.  
  1451.     mc = new Canvas('mainCanvas', AspectMult);
  1452.     mcW = mc.w;
  1453.     mcH = mc.h;
  1454.     mcChange = false;
  1455.  
  1456.     showMap = true;
  1457.  
  1458.     requestFrame = (
  1459.         window.requestAnimationFrame ||
  1460.         window.webkitRequestAnimationFrame ||
  1461.         window.mozRequestAnimationFrame ||
  1462.         window.msRequestAnimationFrame ||
  1463.         function(drawFunc) { return setTimeout(drawFunc, 0); } );
  1464.     cancelFrame = (
  1465.         window.cancelAnimationFrame ||
  1466.         window.webkitCancelAnimationFrame ||
  1467.         window.mozCancelAnimationFrame ||
  1468.         window.msCancelAnimationFrame ||
  1469.         function(id) { clearTimeout(id); } );
  1470.  
  1471.     frames = 0;
  1472.     if(Debug) {
  1473.         setInterval(showFPS, 1000);
  1474.     } else {
  1475.         var fps = document.getElementById('fpsText');
  1476.         fps.innerHTML = '';
  1477.     }
  1478.  
  1479.     init();
  1480. }
  1481.  
  1482. function init() {
  1483.     cancelFrame(frameID[1]);
  1484.     mc.ct.globalAlpha = 1.0;
  1485.     if(mcChange) {
  1486.         mc.updateSize(mcW, mcH, AspectMult);
  1487.         mcChange = false;
  1488.     }
  1489.  
  1490.     plrSpeed = 0.0;
  1491.     mapZoom = 2.0;
  1492.     goalRad = mc.a/6;
  1493.     goalAngle = 0.0;
  1494.     goalAlpha = getGoalAlpha();
  1495.     winState = false;
  1496.     keys = {
  1497.         w: 0, s: 0, a: 0, d: 0, q: 0, e: 0, r: 0, f: 0, z: 0, x: 0, c: 0, v: 0,
  1498.         tab: false, spc: false, minus: false, plus: false };
  1499.     mbstate = [ 0, 0, 0 ];
  1500.     mbpos = { x: -1, y: -1 };
  1501.  
  1502.     // debugging features
  1503.     // criticalFlag flashes the screen red when set to 1.0 for a console message.
  1504.     criticalFlag = 0.0;
  1505.  
  1506.     plr = new SpacePoint(0.5, 0.5, 0.5);
  1507.     restart = new SpacePoint(plr.x, plr.y, plr.z);
  1508.     map = new Map(inW, inH, inD);
  1509.     map.makeMaze(int(plr.x), int(plr.y), int(plr.z));
  1510.  
  1511.     tm = identityMatrix();
  1512.     if(map.d == 1 || map.getCell(int(plr.x), int(plr.y), int(plr.z)+1) == 1) {
  1513.         tm = rotateMatrix(tm, 0, 0, -Pi/2);
  1514.         tm = rotateMatrix(tm, 0, -Pi/2, 0);
  1515.         if(map.h == 1 || map.getCell(int(plr.x), int(plr.y)+1, int(plr.z)) == 1) {
  1516.             tm = rotateMatrix(tm, 0, 0, -Pi/2);
  1517.             tm = rotateMatrix(tm, 0, -Pi/2, 0);
  1518.         }
  1519.     }
  1520.  
  1521.     map.setAllPaths();
  1522.  
  1523.     var polyPoints = new Array(map.w*map.h*map.d);
  1524.     for(var z = 0; z < map.sd; z++)
  1525.     for(var y = 0; y < map.sh; y++)
  1526.     for(var x = 0; x < map.sw; x++) {
  1527.         polyPoints[map.getSIndex(x, y, z)] = new SpacePoint(x, y, z);
  1528.     }
  1529.     polyVerts = new Array();
  1530.     polyDrawn = new Array();
  1531.     polyToCube = new Array();
  1532.     var len = prePolies[0].length;
  1533.     for(var i = 0; i < prePolies.length; i++) {
  1534.         var verts = new Array(len);
  1535.         var drawn = new Array(len);
  1536.         for(var j = 0; j < len; j++) {
  1537.             var pt = points[ prePolies[i][len-j-1] ];
  1538.             var sIndex = map.getSIndex(pt.x*map.w, pt.y*map.h, pt.z*map.d);
  1539.             verts[j] = polyPoints[sIndex];
  1540.             drawn[j] = true;
  1541.         }
  1542.         polyVerts.push(verts);
  1543.         polyDrawn.push(drawn);
  1544.         polyToCube.push(null);
  1545.     }
  1546.     for(var z = 0; z < map.d; z++)
  1547.     for(var y = 0; y < map.h; y++)
  1548.     for(var x = 0; x < map.w; x++) {
  1549.         if(map.getCell(x, y, z) == 1) {
  1550.             for(var i = 0; i < prePolies.length; i++) {
  1551.                 if(map.sideExists({ x: x, y: y, z: z }, i)) {
  1552.                     var verts = new Array(len);
  1553.                     var drawn = new Array(len);
  1554.                     for(var j = 0; j < len; j++) {
  1555.                         var pt = points[ prePolies[i][j] ];
  1556.                         var sIndex = map.getSIndex(pt.x+x, pt.y+y, pt.z+z);
  1557.                         verts[j] = polyPoints[sIndex];
  1558.                         if(map.edgeIsDrawn({ x: x, y: y, z: z}, i, j)) {
  1559.                             drawn[j] = true;
  1560.                         } else {
  1561.                             drawn[j] = false;
  1562.                         }
  1563.                     }
  1564.                     polyVerts.push(verts);
  1565.                     polyDrawn.push(drawn);
  1566.                     polyToCube.push({ x: x, y: y, z: z });
  1567.                 }
  1568.             }
  1569.         }
  1570.     }
  1571.  
  1572.     frameID[0] = requestFrame(output);
  1573. }
  1574.  
  1575. function drawMaze() {
  1576.     map.fillSpace(plr, tm);
  1577.     map.setSeenPathCells(plr);
  1578.     map.setVisibleCells(plr);
  1579.     var visPolies = new Array();
  1580.     for(var i = 0; i < polyVerts.length; i++) {
  1581.         var vis = polyToCube[i];
  1582.         if(vis != null && !map.getVCell(vis.x, vis.y, vis.z)) {
  1583.             continue;
  1584.         }
  1585.         var p = polyVerts[i];
  1586.         var d = polyDrawn[i];
  1587.         var s = new Array(polyVerts[0].length);
  1588.         var xa = 0, ya = 0, za = 0;
  1589.         for(var j = 0; j < s.length; j++) {
  1590.             s[j] = map.getSpace(p[j].x, p[j].y, p[j].z);
  1591.             xa += s[j].x;
  1592.             ya += s[j].y;
  1593.             za += s[j].z;
  1594.         }
  1595.         var ahead = false;
  1596.         for(var j = 0; j < s.length; j++) {
  1597.             if(s[j].z >= zNear) {
  1598.                 p = p.slice(j).concat(p.slice(0, j));
  1599.                 d = d.slice(j).concat(d.slice(0, j));
  1600.                 s = s.slice(j).concat(s.slice(0, j));
  1601.                 ahead = true;
  1602.                 break;
  1603.             }
  1604.         }
  1605.         if(ahead) {
  1606.             if(i < 6) {
  1607.                 var c = null;
  1608.             } else {
  1609.                 var c = new SpacePoint(xa/4, ya/4, za/4) };
  1610.             }
  1611.             visPolies.push({ p: p, d: d, s: s, c: c });
  1612.     }
  1613.     // Sort goal point with rest of the polygons
  1614.     var x = map.goal.x+0.5-plr.x, y = map.goal.y+0.5-plr.y, z = map.goal.z+0.5-plr.z;
  1615.     var mat = multiplyMatrices([ [ x, y, z, 1 ] ], tm);
  1616.     x = mat[0][0], y = mat[0][1], z = mat[0][2];
  1617.     goalDis = Math.sqrt(x*x+y*y+z*z);
  1618.     if(winCheck.checked)
  1619.         if(int(plr.x) == map.goal.x && int(plr.y) == map.goal.y && int(plr.z) == map.goal.z)
  1620.             setTimeout(showWinDisplay, 0);
  1621.     if(z >= zNear)
  1622.         visPolies.push({ p: null, d: null, s: null, c: { x: x, y: y, z: z } });
  1623.     visPolies.sort(distanceCompare);
  1624.  
  1625.     for(var i = 0; i < visPolies.length; i++) {
  1626.         var vp = visPolies[i];
  1627.         if(vp.p == null) {
  1628.             // Draw physical goal circle
  1629.             var f = flattenPoint(vp.c, mc);
  1630.             mc.ct.fillStyle = RGBA(223, 31, 31, goalAlpha);
  1631.             mc.ct.beginPath();
  1632.             mc.ct.closePath();
  1633.             var x = vp.c.x, y = vp.c.y, z = vp.c.z;
  1634.             mc.ct.arc(f.x, f.y, goalRad/goalDis, 0, Circ, false);
  1635.             mc.ct.fill();
  1636.             continue;
  1637.         }
  1638.         var flatLines = getFlatLines(vp.s, vp.p, vp.d);
  1639.         if(flatLines == null)
  1640.             continue;
  1641.         // Occlude polygons that have anticlockwise-running vertices.
  1642.         var t0 = flatLines[flatLines.length-1], t1 = flatLines[0];
  1643.         var a0 = Math.atan2(t1.f0.y-t0.f0.y, t1.f0.x-t0.f0.x);
  1644.         var a1 = Math.atan2(t1.f1.y-t0.f0.y, t1.f1.x-t0.f0.x);
  1645.         var delta = (a1-a0)%Circ;
  1646.         if(delta < 0.0)
  1647.             delta += Circ;
  1648.         if(delta < Pi) {
  1649.             mc.ct.beginPath();
  1650.             mc.ct.moveTo(flatLines[0].f0.x, flatLines[0].f0.y);
  1651.             for(var j = 1; j < flatLines.length; j++) {
  1652.                 if(flatLines[j].f0 != null)
  1653.                     mc.ct.lineTo(flatLines[j].f0.x, flatLines[j].f0.y);
  1654.             }
  1655.             mc.ct.closePath();
  1656.             if(i > 5) {
  1657.                 mc.ct.fillStyle = '#fff';
  1658.                 mc.ct.fill();
  1659.             }
  1660.             mc.ct.lineWidth = 1.0;
  1661.             mc.ct.strokeStyle = '#fff';
  1662.             mc.ct.stroke();
  1663.             mc.ct.strokeStyle = '#000';
  1664.             for(var j = 0; j < flatLines.length; j++) {
  1665.                 if(flatLines[j].draw) {
  1666.                     var x0 = flatLines[j].f0.x, y0 = flatLines[j].f0.y;
  1667.                     var x1 = flatLines[j].f1.x, y1 = flatLines[j].f1.y;
  1668.                     mc.ct.beginPath();
  1669.                     mc.ct.moveTo(x0, y0);
  1670.                     mc.ct.lineTo(x1, y1);
  1671.                     mc.ct.stroke();
  1672.                     mc.ct.closePath();
  1673.                 }
  1674.             }
  1675.         }
  1676.     }
  1677.  
  1678.     if(showMap) {
  1679.         // Draw the maze overview map.
  1680.         map.fillOverviewSpace(plr, tm);
  1681.         mc.ct.lineWidth = 1.0;
  1682.         var d = map.maxDim*2;
  1683.         for(var z = 0; z < map.rd; z++)
  1684.         for(var y = 0; y < map.rh; y++)
  1685.         for(var x = 0; x < map.rw; x++) {
  1686.             var pc = map.getPathCell(x, y, z);
  1687.             if(pc.x.type == -1 && pc.y.type == -1 && pc.z.type == -1)
  1688.                 continue;
  1689.             var t = map.getOSpace(x, y, z);
  1690.             var s = { x: t.x*mapZoom, y: t.y*mapZoom, z: t.z*mapZoom+d };
  1691.             if(s.z < zNear)
  1692.                 continue;
  1693.             var f0 = flattenPoint(s, mc);
  1694.             if(x < map.rw-1 && pc.x.view > -1) {
  1695.                 t = map.getOSpace(x+1, y, z);
  1696.                 s = { x: t.x*mapZoom, y: t.y*mapZoom, z: t.z*mapZoom+d };
  1697.                 if(s.z < zNear)
  1698.                     continue;
  1699.                 var f1 = flattenPoint(s, mc);
  1700.                 mc.ct.strokeStyle = getColor(pc.x);
  1701.                 mc.ct.beginPath();
  1702.                 mc.ct.moveTo(f0.x, f0.y);
  1703.                 mc.ct.lineTo(f1.x, f1.y);
  1704.                 mc.ct.stroke();
  1705.                 mc.ct.closePath();
  1706.  
  1707.                 if(pc.x.time > 0) {
  1708.                     pc.x.time = clip(pc.x.time+PathTimeInc, 0.0, 1.0);
  1709.                     if(pc.x.time > 1.0-eps) {
  1710.                         setColor(pc.x);
  1711.                         pc.x.time = 0;
  1712.                     }
  1713.                 }
  1714.             }
  1715.             if(y < map.rh-1 && pc.y.view > -1) {
  1716.                 t = map.getOSpace(x, y+1, z);
  1717.                 s = { x: t.x*mapZoom, y: t.y*mapZoom, z: t.z*mapZoom+d };
  1718.                 if(s.z < zNear)
  1719.                     continue;
  1720.                 var f1 = flattenPoint(s, mc);
  1721.                 mc.ct.strokeStyle = getColor(pc.y);
  1722.                 mc.ct.beginPath();
  1723.                 mc.ct.moveTo(f0.x, f0.y);
  1724.                 mc.ct.lineTo(f1.x, f1.y);
  1725.                 mc.ct.stroke();
  1726.                 mc.ct.closePath();
  1727.  
  1728.                 if(pc.y.time > 0) {
  1729.                     pc.y.time = clip(pc.y.time+PathTimeInc, 0.0, 1.0);
  1730.                     if(pc.y.time > 1.0-eps) {
  1731.                         setColor(pc.y);
  1732.                         pc.y.time = 0;
  1733.                     }
  1734.                 }
  1735.             }
  1736.             if(z < map.rd-1 && pc.z.view > -1) {
  1737.                 t = map.getOSpace(x, y, z+1);
  1738.                 s = { x: t.x*mapZoom, y: t.y*mapZoom, z: t.z*mapZoom+d };
  1739.                 if(s.z < zNear)
  1740.                     continue;
  1741.                 var f1 = flattenPoint(s, mc);
  1742.                 mc.ct.strokeStyle = getColor(pc.z);
  1743.                 mc.ct.beginPath();
  1744.                 mc.ct.moveTo(f0.x, f0.y);
  1745.                 mc.ct.lineTo(f1.x, f1.y);
  1746.                 mc.ct.stroke();
  1747.                 mc.ct.closePath();
  1748.  
  1749.                 if(pc.z.time > 0) {
  1750.                     pc.z.time = clip(pc.z.time+PathTimeInc, 0.0, 1.0);
  1751.                     if(pc.z.time > 1.0-eps) {
  1752.                         setColor(pc.z);
  1753.                         pc.z.time = 0;
  1754.                     }
  1755.                 }
  1756.             }
  1757.         }
  1758.  
  1759.         // Draw goal map circle
  1760.         mc.ct.strokeStyle = '#f44';
  1761.         mc.ct.lineWidth = 2.0;
  1762.         var x = (map.goal.x-plr.x+0.5)/2;
  1763.         var y = (map.goal.y-plr.y+0.5)/2;
  1764.         var z = (map.goal.z-plr.z+0.5)/2;
  1765.         var mat = multiplyMatrices([ [ x, y, z, 1 ] ], tm);
  1766.         x = mat[0][0]*mapZoom;
  1767.         y = mat[0][1]*mapZoom;
  1768.         z = mat[0][2]*mapZoom+d;
  1769.         if(z >= zNear) {
  1770.             var f = flattenPoint({ x: x, y: y, z: z }, mc);
  1771.             mc.ct.beginPath();
  1772.             mc.ct.closePath();
  1773.             mc.ct.arc(f.x, f.y, 4, 0.0, Circ, false);
  1774.             mc.ct.stroke();
  1775.         }
  1776.  
  1777.         // Draw player circle
  1778.         mc.ct.fillStyle = '#0bb';
  1779.         var f = flattenPoint({ x: 0, y: 0, z: d }, mc);
  1780.         mc.ct.beginPath();
  1781.         mc.ct.closePath();
  1782.         mc.ct.arc(f.x, f.y, 4, 0.0, Circ, false);
  1783.         mc.ct.fill();
  1784.     }
  1785.  
  1786.     if(criticalFlag > 0.0) {
  1787.         mc.ct.fillStyle = RGBA(255, 0, 0, 0.5*criticalFlag);
  1788.         mc.ct.fillRect(0, 0, mc.w, mc.h);
  1789.         criticalFlag = clip(criticalFlag-0.006, 0.0, 1.0);
  1790.     }
  1791. }
  1792.  
  1793. function output() {
  1794.     mc.ct.clearRect(0, 0, mc.w, mc.h);
  1795.     drawMaze();
  1796.     handleRotation();
  1797.     handleMovement();
  1798.     handleMapKeys();
  1799.     goalAlpha = getGoalAlpha();
  1800.     frames++;
  1801.     frameID[0] = requestFrame(output);
  1802. }
  1803.  
  1804. function showWinDisplay() {
  1805.     cancelFrame(frameID[0]);
  1806.     winState = true;
  1807.     bc = new Canvas([ mc.w, mc.h ], AspectMult);
  1808.     bc.ct.clearRect(0, 0, bc.w, bc.h);
  1809.     bc.ct.drawImage(mc.cv, 0, 0);
  1810.     wc = new Canvas([ mc.w, mc.h ], AspectMult);
  1811.     wc.ct.fillStyle = '#fff';
  1812.     wc.ct.fillRect(0, 0, wc.w, wc.h);
  1813.     var msgs = [
  1814.         'you have completed', 'stage one maze', '',
  1815.         'good job', '',
  1816.         'stage two is', 'under development' ];
  1817.     var size = int(mc.h/12);
  1818.     var grad = wc.ct.createRadialGradient(wc.hw, wc.hh, 0, wc.hw, wc.hh, wc.hh);
  1819.     grad.addColorStop(0.0, '#0f0');
  1820.     grad.addColorStop(1.0, '#080');
  1821.     wc.ct.fillStyle = grad;
  1822.     wc.ct.strokeStyle = '#080';
  1823.     wc.ct.lineWidth = 1.0;
  1824.     wc.ct.font = size.toString()+'px sans-serif';
  1825.     wc.ct.textAlign = 'center';
  1826.     wc.ct.textBaseline = 'middle';
  1827.     for(var i = 0; i < msgs.length; i++) {
  1828.         var y = wc.hh+(i-msgs.length/2)*size*1.2;
  1829.         wc.ct.fillText(msgs[i], wc.hw, y);
  1830.         wc.ct.strokeText(msgs[i], wc.hw, y);
  1831.     }
  1832.     winAlpha = 0.0;
  1833.     editBtnPressed = false;
  1834.     onEditBtn()
  1835.     winDisplay();
  1836. }
  1837.  
  1838. function winDisplay() {
  1839.     winAlpha = clip(winAlpha+0.01, 0.0, 1.0);
  1840.     mc.ct.clearRect(0, 0, mc.w, mc.h);
  1841.     mc.ct.globalAlpha = 1.0;
  1842.     mc.ct.drawImage(bc.cv, 0, 0);
  1843.     mc.ct.globalAlpha = winAlpha;
  1844.     mc.ct.drawImage(wc.cv, 0, 0);
  1845.     frameID[1] = requestFrame(winDisplay);
  1846. }
  1847.  
  1848. function renderPrompt(msg) {
  1849.     var size = int(mc.h/10);
  1850.     var grad = mc.ct.createRadialGradient(mc.hw, mc.hh, 0, mc.hw, mc.hh, mc.hh);
  1851.     grad.addColorStop(0.0, '#0bb');
  1852.     grad.addColorStop(1.0, '#066');
  1853.     mc.ct.fillStyle = grad;
  1854.     mc.ct.strokeStyle = '#066';
  1855.     mc.ct.lineWidth = 1.0;
  1856.     mc.ct.font = size.toString()+'px sans-serif';
  1857.     mc.ct.textAlign = 'center';
  1858.     mc.ct.textBaseline = 'middle';
  1859.     mc.ct.fillText(msg, mc.hw, mc.hh);
  1860.     mc.ct.strokeText(msg, mc.hw, mc.hh);
  1861. }
  1862.  
  1863. window.addEventListener('load', preInit, false);</script>
  1864. </body>
  1865.  
  1866. </html>
Advertisement
Add Comment
Please, Sign In to add comment