# Buff definitions
name: buff
+lookup: .tanks.data.buffs
defaults:
symbol: tanks/effects/buff.Buff
timeout: -1 # the Infinity literal is not valid JSON
# Item definitions
name: item
+lookup: .tanks.data.items
defaults:
symbol: tanks/thing/item.Item
types:
+# Level definitions
+name: level
+lookup: .tanks.data.levels
+defaults:
+ symbol: tanks/map/level.Level
+types:
+ test:
+ name: Da Test
+ desc: A test level.
+ width: 500
+ height: 500
+ # bounds: [[-1,-1], [501,-1], [501,351], [351,351], [351,501], [-1,501]]
+ # bounds:
+ # top: [[-50,-50, 600,50]]
+ # left: [[-50,0, 50,500]]
+ # right: [[501,0, 551,351], [351,351, 401,501]]
+ # bottom: [[-50,501, 401,551]]
+ bounds:
+ - [-50,-50, 600,50]
+ - [-50,0, 50,500]
+ - [501,0, 50,500]
+ - [-50,501, 600,50]
+ # - [351,351, 200,200]
+ walls:
+ - [300,50, 50,200] # [x,y, w,h]
+ - [300,350, 50,100]
+ - [50,350, 100,100]
+ - [150,300, 50,50]
+ - [100,100, 50,50]
+ units:
+ - type: player
+ align: 1
+ loc: [275,475]
+ - type: blue
+ align: 1
+ loc: [175,475]
+ - type: green
+ align: 2
+ loc: [25,375]
+ - type: green
+ align: 2
+ loc: [75,25]
+ - type: green
+ align: 2
+ loc: [425,75]
+ items: []
+ events: []
+ art:
+ bg: ''
+ doodads: []
# Unit definitions
name: unit
+lookup: .tanks.data.units
defaults:
symbol: tanks/thing/thing.Thing
level: 1
name: Player
desc: "Don't hate the Player, hate the--Wait. No, that's fine."
tags: [ 'tank' ]
- symbol: tanks/thing/player.PlayerTank
+ symbol: tanks/thing/player.Player
stats:
hp : 1
move : 0.90
if v is not True: kwargs.append(str(v))
return sh('commonjs %s' % ' '.join( SRC_DIRS + kwargs + list(args)), capture=capture)
+
@task
def data():
"Convert all yaml files to json."
, del = require('Y/delegate')
, type = require('Y/type')
, op = require('Y/op')
-, mixInto = require('Y/utils').mixInto
+, proxy = require('Y/utils').proxy
, YCollection = require('Y/types/collection').YCollection
, _Array = Array
var newYArray = YArray.instantiate.bind(YArray);
- mixInto({ target:YArray, donor:_Array, context:'_o',
+ proxy({ target:YArray, donor:_Array, context:'_o',
names:'indexOf lastIndexOf shift join'.split(' ') });
- mixInto({ target:YArray, donor:_Array, context:'_o', chain:true,
+ proxy({ target:YArray, donor:_Array, context:'_o', chain:true,
names:'push unshift sort splice reverse'.split(' ') });
- mixInto({ target:YArray, donor:_Array, context:'_o', fnFirst:true, wrap:newYArray,
+ proxy({ target:YArray, donor:_Array, context:'_o', fnFirst:true, wrap:newYArray,
names:'map forEach filter'.split(' ') });
- mixInto({ target:YArray, donor:_Array, context:'_o', fnFirst:true,
+ proxy({ target:YArray, donor:_Array, context:'_o', fnFirst:true,
names:['reduce', 'some', 'every'] });
- mixInto({ target:YArray, donor:_Array, context:'_o', wrap:newYArray,
+ proxy({ target:YArray, donor:_Array, context:'_o', wrap:newYArray,
names:['slice'] });
var YCollection = require('Y/types/collection').YCollection
-, mixInto = require('Y/utils').mixInto
+, proxy = require('Y/utils').proxy
, op = require('Y/op')
, core = require('Y/core')
, del = require('Y/delegate')
YCollection.subclass('YString', function(YString){
var newYString = YString.instantiate.bind(YString);
- mixInto({ target:YString, donor:String, context:'_o', wrap:newYString,
+ proxy({ target:YString, donor:String, context:'_o', wrap:newYString,
names:'slice substr substring concat replace toLowerCase toUpperCase'.split(' ') });
- mixInto({ target:YString, donor:String, context:'_o',
+ proxy({ target:YString, donor:String, context:'_o',
names:'split indexOf lastIndexOf charAt charCodeAt'.split(' ') });
function trim(val){
var
-This = mixInto['This'] = {},
-Target = mixInto['Target'] = {},
+This = proxy['This'] = {},
+Target = proxy['Target'] = {},
defaults = {
/**
* {Object|Function} target Required. Target object onto which methods will be added. If this a Function, it's prototype will be used.
'names' : null,
/**
- * {mixInto.This|mixInto.Target|String} [context=mixInto.This]
+ * {proxy.This|proxy.Target|String} [context=proxy.This]
* Sets the call context for the function.
- * - {mixInto.This}: (Default) Use runtime `this` as context.
- * - {mixInto.Target}: Use `target` as context.
+ * - {proxy.This}: (Default) Use runtime `this` as context.
+ * - {proxy.Target}: Use `target` as context.
* - {String}: Names a property on `this` to use. If specified and property is false-y, `this` is used.
*/
'context' : This,
*/
'fnFirst' : false
};
-function mixInto(options){
+function proxy(options){
var o = core.extend({}, defaults, options)
, target = o.target
, donor = o.donor
}
exports['bindAll'] = bindAll;
-exports['mixInto'] = mixInto;
+exports['proxy'] = proxy;
var initialise = instance.__initialise__;
if ( isFunction(initialise) )
- return initialise.apply(instance, args);
+ initialise.apply(instance, args);
+
+ cls.fire('created', instance, {
+ 'instance' : instance,
+ 'cls' : cls,
+ 'args' : Y(args)
+ });
}
return instance;
eval(constructor);
- // Copy Class statics
- // for (var i=0, L=classStatics.length; i<L; ++i) {
- // var k = classStatics[i];
- // NewClass[k] = ClassFactory[k];
- // }
-
// Copy parent methods, then add new instance methods
for (var k in parentMembers)
if ( hasOwn.call(parentMembers,k) )
setDesc(prototype, k, getDesc(members,k));
}
+ NewClass.instantiate = instantiate.partial(NewClass);
// prototype.__bind__ = Y([]).concat(prototype.__bind__||[], SuperClass.fn.__bind__||[]).unique();
// Notify mixins to let them finish up any customization
this.remove();
this.dirty = true;
+ if ( !(parent instanceof Layer) && (parent.shape instanceof Layer) )
+ parent = parent.shape;
+
// Layer? Add self as new child, fix DOM
if ( parent instanceof Layer ) {
this.parent = parent;
this.parent.children.remove(this);
this.parent = null;
this.layer.remove();
+ return this;
},
/**
if (w === undefined && h === undefined)
return new Vec(this.layerWidth,this.layerHeight);
+ if (w === null) w = this.layerWidth;
+ if (h === null) h = this.layerHeight;
+
this.layerWidth = w;
this.layerHeight = h;
});
this.canvas.css({
'width' : cw, 'height' : ch,
- 'margin-left' : -nb.x, 'top' : -nb.y
+ 'margin-left' : -nb.x, 'margin-top' : -nb.y
});
var el = this.canvas[0];
el.width = cw;
resolve : function resolve(spec){
var nameParts = spec.split('.')
, modName = nameParts.shift()
- ;
- if (!(modName && modName.length && nameParts.length))
- this.die('Cannot resolve symbol: '+spec);
+ , module ;
- var module = require(modName)
- , symbol = getNested(module, nameParts)
- ;
+ if (!modName)
+ module = window;
+ else
+ module = require(modName);
+
+ if (!nameParts.length)
+ this.die('Cannot resolve symbol: '+spec);
+ var symbol = getNested(module, nameParts)
if (!symbol)
this.die('Unable to locate class specified by symbol (symbol="'+spec+'", module='+module+' --> '+symbol+')!');
- if (!Y.isFunction(symbol.speciate))
- this.die('Cannot create types from data (symbol-class '+symbol+' from "'+spec+'" is not Speciated)!');
return symbol;
},
// console.group('DataFile: processing '+this.path);
var types = Y(data.types)
- , defaults = data.defaults || {};
+ , defaults = data.defaults || {}
+ , lookup = this.resolve(data.lookup)
+ ;
if (!(types && Y.isFunction(types.forEach)))
this.die('Specified types are not iterable! '+data.types);
this.die('No symbol defined for type "'+id+'" at '+this.path+'!');
delete props.symbol;
- var base = this.resolve(symbol)
- , type = base.speciate(id, props);
+ var base = this.resolve(symbol);
+
+ if (!Y.isFunction(base.speciate))
+ this.die('Cannot create types from data (symbol-class '+base+' from "'+symbol+'" is not Speciated)!');
+
+ var type = base.speciate(id, props);
+ lookup[id] = type;
+
// console.log('Added type '+id+':', type);
}, this);
this.clear();
},
+ resize : function resize(x1,y1, x2,y2){
+ Rect.call(this, x1,y1, x2,y2);
+ return this;
+ },
/**
* Determines if the given Rect overlaps with this tree,
ui : {
createGridCanvas : true,
createGridTable : false,
+ overlayOnPause : true,
showGridCoords : false,
showAttackCooldown : false,
showCountdown : (document.location.host.toString() !== 'tanks.woo')
/// Load Data Files ///
var files =
- 'types/buffs types/items types/units' // types/level levels game
+ 'types/buffs types/items types/units types/levels' // levels game
.split(' ')
.map(function(type){
return new DataFile('build/data/'+type+'.json');
, PathMapUI = require('tanks/ui/pathmapui').PathMapUI
, Level = map.Level
-, Thing = thing.Thing, Tank = thing.Tank, Bullet = thing.Bullet
+, Thing = thing.Thing
+, Tank = thing.Tank
+, Bullet = thing.Bullet
+, Player = thing.Player
,
this.viewport = $(viewport || GRID_ELEMENT);
this.loop = new EventLoop(FRAME_RATE, this);
- this.root =
- this.grid =
+ this.root =
+ this.grid =
new Grid(COLUMNS,ROWS, REF_SIZE)
.appendTo(this.viewport);
this.level =
- new Level(this, COLUMNS*REF_SIZE, ROWS*REF_SIZE)
+ Level.create('test', this, CAPACITY, REF_SIZE)
.appendTo(this.root);
- var pathmap = this.pathmap = this.level.pathmap;
- pathmap.ui = new PathMapUI(this, pathmap);
- this.level.append(pathmap.ui);
+ this.pathmap = this.level.pathmap;
+ this.pathmap.ui = new PathMapUI(this, this.pathmap);
+ this.root.append(this.pathmap.ui);
- Thing.addEventListener('init', this.addThing);
+ // automatically keep track of units
+ Thing.addEventListener('created', this.addThing);
Thing.addEventListener('destroy', this.killThing);
-
this.addEventListener('tick', this.tick);
+ this.level.setup();
this.fire('ready', this);
},
destroy : function destroy(){
- Thing.removeEventListener('init', this.addThing);
+ Thing.removeEventListener('created', this.addThing);
Thing.removeEventListener('destroy', this.killThing);
this.stop();
this.resetGlobals();
SQUARETH = REF_SIZE * SECONDTH;
},
+ // get width(){ return this.level.width; },
+ // get height(){ return this.level.height; },
+
draw : function draw(){
this.root.draw();
},
return animation;
},
- addThing : function addThing(unit, col,row){
+ addThing : function addThing(unit, x,y){
if (unit instanceof Event)
unit = unit.trigger;
unit.game = this;
- if (col !== undefined) {
- // Center unit in square
- var sqX = (col || 0) * REF_SIZE
- , sqY = (row || 0) * REF_SIZE
- , x = sqX + REF_SIZE/2
- , y = sqY + REF_SIZE/2 ;
-
+ if (x !== undefined) {
unit.position(x,y);
unit.render( this.level );
+ } else if ( unit.isRenderable ) {
+ unit.render( this.level );
}
this.pathmap.addBlocker(unit);
this.units.push(unit);
}
+ if (unit instanceof Player) {
+ if ( this.player && unit !== this.player )
+ throw new Error('wtf errant player created!');
+ this.player = unit;
+ }
+
return unit;
},
'ui' : require('tanks/ui'),
'Game' : require('tanks/game').Game,
- 'game' : null
+ 'game' : null,
+ 'data' : { 'buffs':{}, 'items':{}, 'units':{}, 'levels':{}, 'bullets':{} }
};
var Y = require('Y').Y
, op = require('Y/op')
-
+, proxy = require('Y/utils').proxy
+, evt = require('evt')
, Rect = require('ezl/shape').Rect
, Buff = require('tanks/effects/buff').Buff
+, PathMap = require('tanks/map/pathmap').PathMap
, Thing = require('tanks/thing/thing').Thing
, Tank = require('tanks/thing/tank').Tank
, Item = require('tanks/thing/item').Item
-, PlayerTank = require('tanks/thing/player').PlayerTank
-, PathMap = require('tanks/map/pathmap').PathMap
+, Player = require('tanks/thing/player').Player
, Wall = require('tanks/thing/wall').Wall
+, Speciated = require('tanks/mixins/speciated').Speciated
+
+, min = Y(Math.min).limit(2)
+, max = Y(Math.max).limit(2)
,
Level =
exports['Level'] =
-Rect.subclass('Level', {
+new evt.Class('Level', {
+ __mixins__ : [ Speciated ],
_cssClasses : 'ezl layer level',
- init : function init(game, w,h){
- Rect.init.call(this, w,h);
- this.canvas.remove();
-
- this.game = game;
- this.walls = Y([]);
- this.allWalls = Y([]);
- this.pathmap = new PathMap(this, 0,0, w, h, CAPACITY);
+ // bounds : [],
+ // walls : [
+ // [300,50, 50,200],
+ // [300,350, 50,100],
+ // [50,350, 100,100],
+ // [150,300, 50,50],
+ // [100,100, 50,50]
+ // ],
+
+
+ init : function init(game, capacity, buffer_size){
+ this.game = game;
+ this.pathmap = new PathMap(0,0, this.width, this.height, capacity, buffer_size);
- game.addEventListener('ready', this.setup.bind(this));
+ var shape = this.shape = new Rect(this.width,this.height).fill('transparent');
+ shape.layer.attr('class', this._cssClasses);
+ this.bbox = shape.bbox;
},
setup : function setup(){
var game = this.game;
- Y.map([ [6,1, 1,4],
- [6,7, 1,2],
- [1,7, 2,2],
- [3,6, 1,1],
- [2,2, 1,1] ],
- "this.addWall.apply(this, Y.map(_, '*REF_SIZE'))",
- this );
+ this.bounds =
+ Y(this.bounds).map(function(wall){
+ return Wall.instantiate.apply(Wall, wall.concat([true]));
+ });
- P =
- game.player = game.addThing(PlayerTank.create('player', 1), 5,9);
- game.addThing(Tank.create('blue', 1), 3,9);
+ this.walls =
+ Y(this.walls).map(function(wall){
+ return Wall.instantiate.apply(Wall, wall);
+ });
- E =
- game.addThing(Tank.create('green', 2), 0,7);
- game.addThing(Tank.create('green', 2), 1,0);
- game.addThing(Tank.create('green', 2), 8,1);
+ var unitdata = tanks.data.units;
+ this.units.map(function(u){
+ var unit = unitdata[u.type].instantiate(u.align);
+ return game.addThing(unit, u.loc[0], u.loc[1]);
+ });
- I =
- game.addThing(Item.create('nitro'), 8,8);
- },
-
- addWall : function addWall(x,y, w,h, isBoundary){
- var wall = new Wall(x,y, w,h, isBoundary);
- this.pathmap.addBlocker(wall);
- this.append( wall.render(this).shape );
+ // P =
+ // game.player = game.addThing(Player.create('player', 1), 5,9);
+ // game.addThing(Tank.create('blue', 1), 3,9);
- this.allWalls.push(wall);
- if (!isBoundary) this.walls.push(wall);
+ // E =
+ // game.addThing(Tank.create('green', 2), 0,7);
+ // game.addThing(Tank.create('green', 2), 1,0);
+ // game.addThing(Tank.create('green', 2), 8,1);
- return wall;
- },
-
- render : op.nop
+ // I =
+ // game.addThing(Item.create('nitro'), 8,8);
+
+ return this;
+ }
-});
\ No newline at end of file
+});
+
+proxy({ target:Level, donor:Rect, context:'shape', chain:true,
+ names:'append appendTo remove invoke clear'.split(' ') });
+
+Level.addEventListener('speciate',
+ function onSpeciate(evt){
+ var NewLevel = evt.data.species
+ , proto = NewLevel.fn
+ , bounds = Y(proto.bounds)
+ ;
+
+ if (!proto.width) {
+ proto.width =
+ bounds.right.pluck(0).reduce(max,0)
+ - bounds.left.pluck(0).reduce(min,Infinity);
+ }
+ if (!proto.height) {
+ proto.height =
+ bounds.bottom.pluck(1).reduce(max,0)
+ - bounds.top.pluck(1).reduce(min,Infinity);
+ }
+ });
, config = require('tanks/config').config
, map = require('tanks/map/map')
, Map = map.Map
+, Wall = require('tanks/thing/wall').Wall
, SQRT_TWO = Math.sqrt(2)
- init : function init(level, x1,y1, x2,y2, capacity) {
- x1 -= 1; y1 -= 1; x2 += 1; y2 += 1;
+ init : function init(x1,y1, x2,y2, capacity, buffer_size) {
+ this.buffer_size = buffer_size;
+ x1 -= buffer_size; y1 -= buffer_size;
+ x2 += buffer_size; y2 += buffer_size;
QuadTree.init.call(this, x1,y1, x2,y2, capacity);
this._squares = {};
- this.level = level;
- this.game = level.game;
- this.walls = level.walls;
- this.allWalls = level.allWalls;
+ this.innerWalls = Y([]);
+ this.allWalls = Y([]);
- this.game.addEventListener('ready', this.setup.bind(this, x1,y1, x2,y2));
+ // this.game.addEventListener('ready', this.setup.bind(this, x1,y1, x2,y2));
},
- /**
- * Adds boundary walls and notifies the level.
- * TODO: I hate this. The level shouldn't have shit to do with pathing.
- */
- setup : function setup(x1,y1, x2,y2){
- var w = this.width, h = this.height
- , level = this.level
-
- , BWs = {
- top : [x1,y1, w,1, true],
- bottom : [x1,y2-1, w,1, true],
- left : [x1,y1, 1,h, true],
- right : [x2-1,y1, 1,h, true]
- };
-
- this.boundaryWalls = Y.map(BWs, 'this.level.addWall.apply(this.level, _)', this);
+ addBlocker : function addBlocker(obj){
+ Map.fn.addBlocker.call(this, obj);
+ if (obj instanceof Wall) {
+ if ( !this.allWalls.has(obj) )
+ this.allWalls.push(obj);
+ if ( !(obj.isBoundary || this.innerWalls.has(obj)) )
+ this.innerWalls.push(obj);
+ }
+ return obj;
+ },
+
+ removeBlocker : function removeBlocker(obj){
+ Map.fn.removeBlocker.call(this, obj);
+ if (obj instanceof Wall) {
+ this.innerWalls.remove(obj);
+ this.allWalls.remove(obj);
+ }
+ return obj;
},
wallObstructs : function wallObstructs(line){
- return this.walls.some(function(wall){
+ return this.innerWalls.some(function(wall){
return wall.bbox.intersects(line);
}, this);
},
-
/**
* Takes normal (not gridSquare-relative) coordinates.
*/
pathBlocked : function pathBlocked(obj, ignore){
var blockers =
- this.pathmap.walls
+ this.pathmap.innerWalls
.concat( this.game.units )
.apply('remove', [this.owner].concat(ignore || []) )
.filter( this.intersects )
// TODO: all YString methods to return YString :P But it'll proally break shit
name = Y(name).capitalize();
name = Y(name).snakeToCamel();
- return name;
+ return name+this.className;
},
speciate : function speciate(id, props){
// Instance
blocking : map.BLOCKING,
+ isRenderable : true,
bounces : 0,
bounceLimit : 1,
exports['Wall'] = require('tanks/thing/wall').Wall;
exports['Bullet'] = require('tanks/thing/bullet').Bullet;
exports['Tank'] = require('tanks/thing/tank').Tank;
-exports['PlayerTank'] = require('tanks/thing/player').PlayerTank;
+exports['Player'] = require('tanks/thing/player').Player;
exports['Item'] = require('tanks/thing/item').Item;
// exports['CustomTank'] = require('tanks/thing/customtank').CustomTank;
,
-PlayerTank =
-exports['PlayerTank'] =
-Tank.subclass('PlayerTank', {
+Player =
+exports['Player'] =
+Tank.subclass('Player', {
__mixins__ : [ Inventoried ],
blocking : map.BLOCKING,
var p = new Projectile(this, tx,ty, x,y);
p.addEventListener('destroy', this.onBulletDeath);
- this.game.addThing(p).render(this.game.level);
+ // this.game.addThing(p).render(this.game.level);
return p;
};
// Properties
blocking : map.BLOCKING,
+ isRenderable : false, // Agent will present itself for rendering when ready // FIXME: stupid hack
active : true, // Agent takes actions?
isReflective : false, // Projectiles bounce off agent rather than explode?
hasInventory : false, // Agent can acquire items?
blocking : map.BLOCKING,
isReflective : true,
+ isRenderable : true,
// inactive
active : false,
// As EventLoop is in ezl, it should not know about config
config.updateOnChange('game.timeDilation', EventLoop.fn);
-
-// exports['init'] =
-// function initConfigUi(){
-// $('#config [name=pathmap]').attr('checked', config.get('pathing.overlayPathmap'));
-// $('#config [name=aipaths]').attr('checked', config.get('pathing.overlayAiPaths'));
-// $('#config [name=trajectories]').attr('checked', config.get('pathing.traceTrajectories'));
-//
-// $('#config [name=gridCoords]').attr('checked', config.get('ui.showGridCoords'));
-// $('#viewport .layer.grid')[(config.get('ui.showGridCoords') ? 'add' : 'remove')+'Class']('showGridCoords');
-// };
-//
-// exports['update'] =
-// function updateConfigUi(evt){
-// config.set('pathing.overlayPathmap', $('#config [name=pathmap]').attr('checked'));
-// config.set('pathing.overlayAiPaths', $('#config [name=aipaths]').attr('checked'));
-// config.set('pathing.traceTrajectories', $('#config [name=trajectories]').attr('checked'));
-//
-// config.set('ui.showGridCoords', $('#config [name=gridCoords]').attr('checked'));
-// $('#viewport .layer.grid')[(config.get('ui.showGridCoords') ? 'add' : 'remove')+'Class']('showGridCoords');
-// };
-
-
-
, config = cfg.config
, updateTimer = null
-, LBT = null
+, LBT = null, overlay = null
;
function stopProp(evt){ evt.stopPropagation(); }
function main(){
$('#loading').center();
+ overlay = $('#overlay');
+ updateOverlay( config.get('ui.overlayOnPause') );
+ config.addEventListener('set:ui.overlayOnPause', function(evt){ updateOverlay(evt.newval); });
+
/// Debug ///
if (qkv.ai) {
$('#welcome').hide();
startGame();
});
+
cfg.dataLoader
.addEventListener('complete', function(evt){
$('#loading').hide();
return this;
};
+function updateOverlay(show){
+ if (show)
+ overlay.prependTo('body');
+ else
+ overlay.remove();
+}
+
exports['main'] = main;
exports['gameExists'] = gameExists;
init : function initPathMapUI(game, pathmap){
Y.bindAll(this, 'pathWithUI', 'cleanUpAgent', 'drawPathStep', 'overlayRegion');
- Rect.init.call(this, pathmap.width-2, pathmap.height-2);
+
+ var level = game.level
+ , b = this.buffer = pathmap.buffer_size;
+ Rect.init.call(this, level.width, level.height);
+ // this.posBleed.x = this.posBleed.y =
+ // this.negBleed.x = this.negBleed.y = b;
+
+ this.size(null,null);
this.game = game;
this.pathmap = pathmap;
},
overlay : function overlay(ctx){
+ // console.group('overlay');
this.pathmap.reduce(this.overlayRegion, { 'ctx':ctx });
+ // console.groupEnd();
},
overlayRegion : function overlayRegion(acc, v, r, tree){
var ctx = acc.ctx;
+ // if ( acc[r.id] )
if ( acc[r.id] || v.isBoundary )
return acc;
acc[r.id] = r;
ctx.lineWidth = this.lineWidth;
}
+ // if ( v.isBoundary )
+ // ctx.strokeStyle = 'rgba(231,48,117, 0.5)';
+
ctx.beginPath();
ctx.rect(r.x1,r.y1, r.width,r.height);
ctx.fill();
#ai .ready { width:5%; float:left; margin-right:1em; }
#ai textarea { width:90%; height:100px; }
-#viewport { position:relative; width:500px; height:500px; margin:1em auto; cursor:crosshair; }
+#viewport { position:relative; margin:1em auto; cursor:crosshair; width:500px; height:500px; /* overflow:hidden; top:50px; left:50px; */ }
#viewport .layer.grid { outline:1px solid rgba(255,255,255,0.1); }
#overlay { position:fixed; top:0; left:0; width:100%; height:100%; background-color:#000; opacity:0.5; z-index:1000; }
.showGridCoords table.grid td:hover { color:rgba(255,255,255,0.1); }
.ezl.layer.pathmap { z-index:50; }
+
<script src="build/tanks/mixins/meronomic.js" type="text/javascript"></script>
<script src="build/tanks/map/traversal.js" type="text/javascript"></script>
<script src="build/tanks/config.js" type="text/javascript"></script>
-<script src="build/tanks/map/pathmap.js" type="text/javascript"></script>
<script src="build/tanks/ui/configui.js" type="text/javascript"></script>
<script src="build/tanks/mixins/quantified.js" type="text/javascript"></script>
<script src="build/tanks/thing/thing.js" type="text/javascript"></script>
<script src="build/tanks/effects/buff.js" type="text/javascript"></script>
<script src="build/tanks/map/trajectory.js" type="text/javascript"></script>
<script src="build/tanks/effects.js" type="text/javascript"></script>
-<script src="build/tanks/ui/pathmapui.js" type="text/javascript"></script>
<script src="build/tanks/thing/item.js" type="text/javascript"></script>
<script src="build/tanks/thing/wall.js" type="text/javascript"></script>
<script src="build/tanks/ui/grid.js" type="text/javascript"></script>
<script src="build/tanks/fx/explosion.js" type="text/javascript"></script>
<script src="build/tanks/thing/bullet.js" type="text/javascript"></script>
+<script src="build/tanks/map/pathmap.js" type="text/javascript"></script>
<script src="build/tanks/mixins/inventoried.js" type="text/javascript"></script>
<script src="build/tanks/fx.js" type="text/javascript"></script>
<script src="build/tanks/thing/tank.js" type="text/javascript"></script>
+<script src="build/tanks/ui/pathmapui.js" type="text/javascript"></script>
<script src="build/tanks/mixins.js" type="text/javascript"></script>
<script src="build/tanks/thing/player.js" type="text/javascript"></script>
<script src="build/tanks/map/level.js" type="text/javascript"></script>