renderer for rhombic maps master
authorpaul <paul@plutz.net>
Sun, 21 Jan 2018 19:30:36 +0000 (19:30 +0000)
committerpaul <paul@plutz.net>
Sun, 21 Jan 2018 19:30:36 +0000 (19:30 +0000)
svn path=/trunk/; revision=14

rhombic.html [new file with mode: 0644]

diff --git a/rhombic.html b/rhombic.html
new file mode 100644 (file)
index 0000000..83f7e70
--- /dev/null
@@ -0,0 +1,354 @@
+<!DOCTYPE XHTML>
+<html><head>
+  <title>Tilerender</title>
+  <meta charset="utf8">
+</head><body onload="script()" style="width: 100%; max-height: 600px; overflow: hidden; padding: 0 auto;" >
+  <canvas id="view" width="1280" height="600" style="padding: 0 auto; max-height: 600px;">
+    Canvas not supported<br/>
+    <img id="maptiles" src="tileset.png" width="64" style="overflow: hidden;"  />
+    <tiles>
+      <tile position="0" name="air" fluid="1"></tile>
+      <tile position="1" name="cursor" animated=".125"></tile>
+      <tile position="2" name="grass" animated=".0625"></tile>
+      <tile position="3" name="parquet" elevation=".125"></tile>
+      <tile position="4" name="sand"></tile>
+      <tile position="5" name="dirt" blocking="1"></tile>
+      <tile position="6" name="brick" blocking="1"></tile>
+      <tile position="7" name="water" animated="1" fluid=".5"></tile>
+    </tiles>
+    <img id="character" src="character.png" speed="4"/>
+    <div id="map" columns="32" rows="32">
+      4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 
+      4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 
+      4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 
+      4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 
+      4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 
+      4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 
+      6, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 5, 5, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
+      4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 5, 5, 5, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
+      6, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 5, 5, 5, 5, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
+      4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 5, 5, 5, 5, 5, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
+      6, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 5, 5, 5, 5, 5, 5, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
+      4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 5, 5, 5, 5, 5, 5, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
+      6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 5, 5, 5, 5, 5, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
+      5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 5, 5, 5, 5, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
+      6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 5, 5, 5, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
+      5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 5, 5, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
+      6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 5, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
+      5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
+      6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
+      5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
+      6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
+      5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
+      6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
+      5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
+      6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
+      5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
+      6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
+      5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
+      6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
+      5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
+      6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 5, 
+      5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 
+
+      6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 
+      6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 
+      2, 2, 2, 7, 7, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 
+      2, 2, 7, 7, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 6, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 
+      2, 2, 7, 7, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2, 6, 6, 6, 6, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 
+      2, 7, 7, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 6, 6, 6, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 
+      2, 7, 7, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 6, 4, 4, 6, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 
+      7, 7, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 6, 4, 4, 4, 6, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 
+      7, 7, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 6, 4, 4, 4, 4, 6, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 
+      7, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 6, 4, 4, 4, 4, 4, 6, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 
+      7, 7, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 6, 4, 4, 4, 4, 4, 4, 6, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 
+      7, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 6, 4, 4, 4, 4, 4, 4, 6, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 
+      7, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 6, 4, 4, 4, 4, 4, 6, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 
+      2, 2, 2, 2, 7, 2, 2, 2, 2, 2, 2, 2, 6, 3, 4, 4, 4, 6, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 
+      2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 4, 4, 6, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 
+      2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 4, 4, 6, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 
+      2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 6, 4, 6, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 
+      2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 2, 6, 6, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 
+      2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 6, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 
+      2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 
+      2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 
+      2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 
+      2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 
+      2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 
+      2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 
+      2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 
+      2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 
+      2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 
+      2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 
+      2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 
+      2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 
+      2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 
+    </div>
+  </canvas>
+</body><script>
+var gravity = 9.81, fps = 30;
+view = document.getElementById("view");
+canvas = document.getElementById("view").getContext("2d");
+
+map = {
+  rows: document.getElementById("map").getAttribute("rows") * 1 || 1,
+  cols: document.getElementById("map").getAttribute("columns") * 1 || 1,
+  data: document.getElementById("map").textContent.split(',') || [],
+  tiles: document.getElementById("maptiles"),
+
+  default_props: {animated: false, elevation: 0, blocking: false, fluid: false},
+  tileprops: [],
+  tw: 32, th: 16, sw: 16, sh: 8,
+  offset_x: 0, offset_y: 0,
+
+  init: function(){
+    this.tw = this.tiles.getAttribute("width") * 1 || 32;
+    this.th = this.tiles.getAttribute("height") * 1 || this.tw / 2;
+    this.sw = this.tw / 2;
+    this.sh = this.th / 2;
+
+    this.gravity = gravity / fps / Math.sqrt(this.sw * this.sw + this.sh * this.sh) * this.sh;
+
+    var prop, i;
+
+    for (i in this.data) this.data[i] = this.data[i] * 1 || 0; // make numeric
+
+    for (prop of document.querySelectorAll("tiles > tile")) {
+      i = prop.getAttribute("position") * 1;
+      if (i || i == 0) this.tileprops[i] = {
+        animated:  prop.getAttribute("animated")      || this.default_props.animated,
+        elevation: prop.getAttribute("elevation") * 1 || this.default_props.elevation,
+        blocking:  prop.getAttribute("blocking")      || this.default_props.blocking,
+        fluid:     prop.getAttribute("fluid")         || this.default_props.fluid
+      }
+      if (!this.tileprops[0]) this.tileprops[0] = { animated: false, elevation: 0, blocking: false, fluid: 1 }
+    }
+  },
+
+  props_of: function(n) { return this.tileprops[this.data[n]] || this.tileprops[0]; },
+
+  tile_at: function(x, y, z) {
+    nx = (y - 48) / 32 + (x) / 64 |0;
+    ny = (y - 48) / 32 - (x) / 64 |0;
+
+    return ny * this.cols + nx + (z|0) * this.rows * this.cols;
+  },
+
+  /*
+  tile_at: function(x, y, z) {
+    var my = (y / this.sh |0);
+    var mx = (x / this.sw |0);
+    
+    switch(((my % 2) << 1) + mx % 2) {
+      case 0: my += o = (y % this.sh * 2 > this.sw - x % this.sw);              break;
+      case 1: my += o = (y % this.sh * 2 >           x % this.sw); mx -= o;     break;
+      case 2: my += o = (y % this.sh * 2 >           x % this.sw);              break;
+      case 3: my += o = (y % this.sh * 2 > this.sw - x % this.sw); mx += o - 1; break;
+    }
+    mx -= x / this.tw |0;
+  
+    return this.cols * my + mx + (z |0) * this.rows * this.cols;
+  },
+  */
+
+  draw: function(){
+    var px = player.n % this.cols;
+    var x, y, z = 0, n, tile, props;
+
+    for ( y = 0; y < this.cols * 2; ++y) {
+      xw = (y < this.cols) ? y : this.cols * 2 - y;
+      for (z = 0; z < this.data.length / (this.rows * this.cols); ++z)
+      for ( x = 0; x < xw; ++x) {
+        n = (y <= this.cols) ? x + (y - x) * map.cols : (this.rows - x) * this.cols + (y - this.cols) + x;
+        n = n - this.cols + z * this.cols * this.rows;
+        tile = ( n == ptr ) ? 1 : this.data[n];
+        props = this.tileprops[tile] || this.default_props;
+
+        canvas.drawImage( this.tiles,
+                          this.tw * tile, 2 * this.th * ((props.animated * frame |0) % 8),
+                          this.tw, 2 * this.th,
+                           - xw * this.sw + x * this.tw - this.offset_x,
+                          y * this.sh - this.offset_y - z * this.th,
+                          this.tw, 2 * this.th
+                        );
+        if (player.n == n) player.draw();
+      }
+    }
+  }
+/*
+  draw: function(){ // map.draw
+    var py = player.n / this.cols % this.rows |0;
+    var px = player.n % this.cols;
+    var x, y, z, n, tile, props;
+
+    for (y = 0; y < this.rows; ++y) {
+      for (z = 0; z < this.data.length / (this.rows * this.cols); ++z)
+      for (x = 0; x < this.cols; ++x) {
+        n = x + y * map.cols + z * map.rows * map.cols;
+        tile = ( n == ptr ) ? 1 : this.data[n];
+        props = this.tileprops[tile] || this.default_props;
+
+        canvas.globalAlpha = ( y > py &&
+                               (z > player.z + 1 || z == (player.z |0) && props.blocking) &&
+                               y < py + 6 &&
+                               x > px - 2 &&
+                               x < px + 2 &&
+                               !props.fluid
+                             ) ? .25 : 1;
+  
+        canvas.drawImage( this.tiles,
+                          this.tw * tile, 2 * this.th * ((props.animated * frame |0) % 8),
+                          this.tw, 2 * this.th,
+                          x * this.tw + y % 2 * this.sw - this.sw - this.offset_x,
+                          y * this.sh - z * this.th - 3 * this.sh - this.offset_y,
+                          this.tw, 2 * this.th
+                        );
+      }
+    }
+    player.draw();
+  } // end map.draw
+*/
+} // end map
+
+player = {
+  frame: 0, d: 's',
+  x: 0, y: 17, z: 4,
+  sprite: document.getElementById("character"),
+
+  init: function(){
+    this.w = this.sprite.getAttribute("width")  * 1 || map.tw || 32;
+    this.h = this.sprite.getAttribute("height") * 1 || map.sh * 6 || this.w * 1.5;
+    this.o = this.sprite.getAttribute("offset") * 1 || map.sh || this.w / 4;
+    this.ospeed = this.speed = this.sprite.getAttribute("speed") * 1|| this.w / 16;
+    this.n = map.tile_at(this.x, this.y, this.z);
+    map.offset_x = this.x - view.clientWidth / 2 |0;
+    map.offset_y = this.y - view.clientHeight / 2 |0;
+  },
+
+  move: function(){ // player.move
+    var dx = 0, dy = 0;
+  
+    switch(this.d){
+      case  'n': dy = -this.speed; break;
+      case  's': dy =  this.speed; break;
+      case  'w': dx = -this.speed; break;
+      case  'e': dx =  this.speed; break;
+      case 'nw': dy = -.45 * this.speed; dx = -.9 * this.speed; break;
+      case 'ne': dy = -.45 * this.speed; dx =  .9 * this.speed; break;
+      case 'sw': dy =  .45 * this.speed; dx = -.9 * this.speed; break;
+      case 'se': dy =  .45 * this.speed; dx =  .9 * this.speed; break;
+    }
+
+    if (player.frame % 6 > 2) { dx *= 1.375; dy *= 1.375; }
+    else { dx *= .625; dy *= .625; }
+  
+    var n = map.tile_at(this.x + dx, this.y + dy, this.z);
+    var prop = map.props_of(n), head = map.props_of(n + map.rows * map.cols);
+
+    if      (prop.fluid) { dx *= prop.fluid; dy *= prop.fluid; }
+    else if (head.fluid) { dx *= head.fluid; dy *= head.fluid; }
+
+    if (!prop.blocking && head.fluid) { 
+      this.x += dx; this.y += dy; this.n = n;
+    }
+
+    this.frame += this.frame < 255 ? 1 : -127;
+
+    map.offset_x = this.x - view.clientWidth / 2 |0;
+    map.offset_y = this.y - view.clientHeight / 2 |0;
+  }, // end player.move
+
+  zspeed: 0,
+  fall: function(){
+    var props = map.props_of(this.n);
+    var bottom = map.props_of(this.n - map.rows * map.cols);
+    var zbase = (this.n / (map.rows * map.cols) |0) + props.elevation;
+
+    this.z += this.zspeed -= map.gravity;
+
+    if (this.z > zbase) {
+      this.speed = this.ospeed * 2;
+    } else if (props.fluid && !bottom.blocking) {
+      this.n -= map.rows * map.cols;
+    } else {
+      this.speed = this.ospeed;
+      this.zspeed = 0;
+      this.z = zbase;
+    }
+
+  }, // end player.fall
+
+
+  draw: function(){ // player.draw
+    var face = 0, state = 0;
+  
+    switch (this.d){
+      case  's': face = 0; break;
+      case 'sw': face = 1; break;
+      case  'w': face = 2; break;
+      case 'nw': face = 3; break;
+      case  'n': face = 4; break;
+      case 'ne': face = 5; break;
+      case  'e': face = 6; break;
+      case 'se': face = 7; break;
+    }
+  
+    state = 
+      (this.frame > 11) ? frame / 16 % 2 |0 :
+      (this.frame < 12) ? this.frame / 3 + 2 |0 :
+      0;
+  
+    canvas.drawImage( this.sprite, this.w * face, this.h * state,
+                      this.w, this.h,
+                      this.x - this.w / 2 - map.offset_x,
+                      this.y - this.h + this.o - map.offset_y - this.z * map.th,
+                      this.w, this.h );
+   
+  } // end player.draw
+};
+
+frame = 0;
+move = true;
+keys = [];
+ptr = 0;
+
+function get_input(){
+  d = '';
+  if ( keys[87] || keys[38] ) d  = 'n';
+  if ( keys[83] || keys[40] ) d  = 's';
+  if ( keys[65] || keys[37] ) d += 'w';
+  if ( keys[68] || keys[39] ) d += 'e';
+
+  if ( d == '' ) player.frame = 12
+  else {
+    player.d = d;
+    if ( player.frame > 11 ) player.frame = 0;
+    player.move();
+  }
+
+  // jump
+  if (keys[32] && player.zspeed == 0) {player.zspeed += .75; player.z +=.0001;}
+}
+
+function script(){
+  map.init();
+  player.init();
+
+  setInterval(function(){
+    get_input();
+    player.fall();
+    map.draw();
+    frame += frame < 255 ? 1 : -255;
+  }, 1000 / fps);
+
+  window.addEventListener('keydown', function(x){ keys[x.keyCode] = true; }, false );
+  window.addEventListener('keyup',   function(x){ keys[x.keyCode] = false;}, false );
+
+  window.addEventListener('mousemove', function(e){
+    px = view.width  * (e.clientX - view.offsetLeft) / view.clientWidth |0;
+    py = view.height * (e.clientY - view.offsetTop) / view.clientHeight |0;
+
+    ptr = map.tile_at(px + map.offset_x, py + map.offset_y, 0);
+  })
+}
+</script></html>