--- /dev/null
+html{color:#000;background:#FFF;}body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,pre,code,form,fieldset,legend,input,textarea,p,blockquote,th,td{margin:0;padding:0;}table{border-collapse:collapse;border-spacing:0;}fieldset,img{border:0;}address,caption,cite,code,dfn,em,strong,th,var{font-style:normal;font-weight:normal;}li{list-style:none;}caption,th{text-align:left;}h1,h2,h3,h4,h5,h6{font-size:100%;font-weight:normal;}q:before,q:after{content:'';}abbr,acronym {border:0;font-variant:normal;}sup {vertical-align:text-top;}sub {vertical-align:text-bottom;}input,textarea,select{font-family:inherit;font-size:inherit;font-weight:inherit;}input,textarea,select{*font-size:100%;}legend{color:#000;}
+h1{font-size:138.5%;}h2{font-size:123.1%;}h3{font-size:108%;}h1,h2,h3{margin:1em 0;}h1,h2,h3,h4,h5,h6,strong{font-weight:bold;}abbr,acronym{border-bottom:1px dotted #000;cursor:help;} em{font-style:italic;}blockquote,ul,ol,dl{margin:1em;}ol,ul,dl{margin-left:2em;}ol li{list-style:decimal outside;}ul li{list-style:disc outside;}dl dd{margin-left:1em;}th,td{padding:.5em;}th{font-weight:bold;text-align:center;}caption{margin-bottom:.5em;text-align:center;}p,fieldset,table,pre{margin-bottom:1em;}input[type=text],input[type=password],textarea{width:12.25em;*width:11.9em;}
\ No newline at end of file
--- /dev/null
+<!DOCTYPE html>
+<html>
+<head>
+<title>The Littlest Battletank</title>
+<link rel="stylesheet" href="css/reset.css" type="text/css" media="screen">
+<link rel="stylesheet" href="css/lttl.css" type="text/css" media="screen">
+</head>
+<body class="lttl tanks">
+
+
+<div id="viewport"></div>
+
+<h1>The Littlest Battletank</h1>
+
+<ul id="info" class="rounded">
+ <li id="state"></li>
+ <li><label for="fps">fps</label> <input id="fps" name="fps" value="" type="text"></li>
+ <li><label for="frame">frame</label> <input id="frame" name="frame" value="" type="text"></li>
+ <li><label for="agents">agents</label> <input id="agents" name="agents" value="" type="text"></li>
+ <li><label for="units">units</label> <input id="units" name="units" value="" type="text"></li>
+ <li><label for="bullets">bullets</label> <input id="bullets" name="bullets" value="" type="text"></li>
+</ul>
+
+<div id="log" style="display:none"></div>
+
+<div id="scripts">
+ <!--[if IE]><script type="text/javascript" src="lib/excanvas.min.js"></script><![endif]-->
+<?php
+$scripts = array(
+ "lib/jquery-1.4.3.js",
+ "lib/jquery.hotkeys.js",
+
+ // "http://static.ukijs.org/pkg/0.3.8/uki.js",
+ // "http://static.ukijs.org/pkg/0.3.8/uki-more.js",
+
+ "src/lessly/future.js",
+
+ "src/Y/y.js.php",
+ "src/Y/modules/y.event.js",
+
+ "src/portal/layer.js",
+ "src/portal/shape.js",
+
+ // "src/portal/util/quadtree.js",
+ // "src/portal/util/rbtree.js",
+ // "src/portal/util/eventloop.js",
+ // "src/portal/util/cooldown.js",
+ // "src/portal/util/loc.js",
+
+ "src/tanks/map.js",
+ "src/tanks/tank.js",
+ "src/tanks/game.js",
+ "src/tanks/ui.js",
+
+ "src/tanks/lttl.js"
+);
+
+function js($src) {
+ echo " <script src=\"$src\" type=\"text/javascript\"></script>\n";
+}
+
+foreach ($scripts as $s) js($s);
+?>
+</div>
+
+</body>
+</html>
\ No newline at end of file
--- /dev/null
+/*
+CAKE - Canvas Animation Kit Experiment
+
+Copyright (C) 2007 Ilmari Heikkinen
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation
+files (the "Software"), to deal in the Software without
+restriction, including without limitation the rights to use,
+copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following
+conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+
+/**
+ Delete the first instance of obj from the array.
+
+ @param obj The object to delete
+ @return true on success, false if array contains no instances of obj
+ @type boolean
+ @addon
+ */
+Array.prototype.deleteFirst = function(obj) {
+ for (var i=0; i<this.length; i++) {
+ if (this[i] == obj) {
+ this.splice(i,1)
+ return true
+ }
+ }
+ return false
+}
+
+Array.prototype.stableSort = function(cmp) {
+ // hack to work around Chrome's qsort
+ for(var i=0; i<this.length; i++) {
+ this[i].__arrayPos = i;
+ }
+ return this.sort(Array.__stableSorter(cmp));
+}
+Array.__stableSorter = function(cmp) {
+ return (function(c1, c2) {
+ var r = cmp(c1,c2);
+ if (!r) { // hack to work around Chrome's qsort
+ return c1.__arrayPos - c2.__arrayPos
+ }
+ return r;
+ });
+}
+
+/**
+ Compares two arrays for equality. Returns true if the arrays are equal.
+ */
+Array.prototype.equals = function(array) {
+ if (!array) return false
+ if (this.length != array.length) return false
+ for (var i=0; i<this.length; i++) {
+ var a = this[i]
+ var b = array[i]
+ if (a.equals && typeof(a.equals) == 'function') {
+ if (!a.equals(b)) return false
+ } else if (a != b) {
+ return false
+ }
+ }
+ return true
+}
+
+/**
+ Rotates the first element of an array to be the last element.
+ Rotates last element to be the first element when backToFront is true.
+
+ @param {boolean} backToFront Whether to move the last element to the front or not
+ @return The last element when backToFront is false, the first element when backToFront is true
+ @addon
+ */
+Array.prototype.rotate = function(backToFront) {
+ if (backToFront) {
+ this.unshift(this.pop())
+ return this[0]
+ } else {
+ this.push(this.shift())
+ return this[this.length-1]
+ }
+}
+/**
+ Returns a random element from the array.
+
+ @return A random element
+ @addon
+ */
+Array.prototype.pick = function() {
+ return this[Math.floor(Math.random()*this.length)]
+}
+
+Array.prototype.flatten = function() {
+ var a = []
+ for (var i=0; i<this.length; i++) {
+ var e = this[i]
+ if (e.flatten) {
+ var ef = e.flatten()
+ for (var j=0; j<ef.length; j++) {
+ a[a.length] = ef[j]
+ }
+ } else {
+ a[a.length] = e
+ }
+ }
+ return a
+}
+
+Array.prototype.take = function() {
+ var a = []
+ for (var i=0; i<this.length; i++) {
+ var e = []
+ for (var j=0; j<arguments.length; j++) {
+ e[j] = this[i][arguments[j]]
+ }
+ a[i] = e
+ }
+ return a
+}
+
+if (!Array.prototype.pluck) {
+ Array.prototype.pluck = function(key) {
+ var a = []
+ for (var i=0; i<this.length; i++) {
+ a[i] = this[i][key]
+ }
+ return a
+ }
+}
+
+Array.prototype.set = function(key, value) {
+ for (var i=0; i<this.length; i++) {
+ this[i][key] = value
+ }
+}
+
+Array.prototype.allWith = function() {
+ var a = []
+ topLoop:
+ for (var i=0; i<this.length; i++) {
+ var e = this[i]
+ for (var j=0; j<arguments.length; j++) {
+ if (!this[i][arguments[j]])
+ continue topLoop
+ }
+ a[a.length] = e
+ }
+ return a
+}
+
+// some common helper methods
+
+if (!Function.prototype.bind) {
+ /**
+ Creates a function that calls this function in the scope of the given
+ object.
+
+ var obj = { x: 'obj' }
+ var f = function() { return this.x }
+ window.x = 'window'
+ f()
+ // => 'window'
+ var g = f.bind(obj)
+ g()
+ // => 'obj'
+
+ @param object Object to bind this function to
+ @return Function bound to object
+ @addon
+ */
+ Function.prototype.bind = function(object) {
+ var t = this
+ return function() {
+ return t.apply(object, arguments)
+ }
+ }
+}
+
+if (!Array.prototype.last) {
+ /**
+ Returns the last element of the array.
+
+ @return The last element of the array
+ @addon
+ */
+ Array.prototype.last = function() {
+ return this[this.length-1]
+ }
+}
+if (!Array.prototype.indexOf) {
+ /**
+ Returns the index of obj if it is in the array.
+ Returns -1 otherwise.
+
+ @param obj The object to find from the array.
+ @return The index of obj or -1 if obj isn't in the array.
+ @addon
+ */
+ Array.prototype.indexOf = function(obj) {
+ for (var i=0; i<this.length; i++)
+ if (obj == this[i]) return i
+ return -1
+ }
+}
+if (!Array.prototype.includes) {
+ /**
+ Returns true if obj is in the array.
+ Returns false if it isn't.
+
+ @param obj The object to find from the array.
+ @return True if obj is in the array, false if it isn't
+ @addon
+ */
+ Array.prototype.includes = function(obj) {
+ return (this.indexOf(obj) >= 0);
+ }
+}
+/**
+ Iterate function f over each element of the array and return an array
+ of the return values.
+
+ @param f Function to apply to each element
+ @return An array of return values from applying f on each element of the array
+ @type Array
+ @addon
+ */
+Array.prototype.map = function(f) {
+ var na = new Array(this.length)
+ if (f)
+ for (var i=0; i<this.length; i++) na[i] = f(this[i], i, this)
+ else
+ for (var i=0; i<this.length; i++) na[i] = this[i]
+ return na
+}
+Array.prototype.forEach = function(f) {
+ for (var i=0; i<this.length; i++) f(this[i], i, this)
+}
+if (!Array.prototype.reduce) {
+ Array.prototype.reduce = function(f, s) {
+ var i&nbs